1

I'm trying to update a Listbox item background independently using command as following: Model

public class Item
{
    public Item()
    {
        this.BackColor = new SolidColorBrush(Colors.WhiteSmoke);
    }

    public int Number { get; set; }
    public int Duration { get; set; }
    public string Name { get { return Number.ToString(); } }
    public SolidColorBrush BackColor { get; set; }
}

ViewModel

private ObservableCollection<Item> _items;

public ObservableCollection<Item> Items
{
    get { return _items; }
    set { OnPropertyChange(ref _items, value); }
}

Button command

public ICommand StartCommand { get; set; }

public void start()
{
    foreach (var item in Items
    {
        item.BackColor = new SolidColorBrush(Colors.LightGreen);
        // Do some work .....
    }
}

CTOR

public MainViewModel()
{
    StartCommand = new RelayCommand(start);
    LoadItems();
}

Xaml

<ListBox  ItemsSource="{Binding Items}" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border 
                Height="50" 
                BorderThickness="1" 
                BorderBrush="Silver" 
                CornerRadius="5" 
                Margin="10,10,10,5" 
                Background="{Binding BackColor,
                UpdateSourceTrigger=PropertyChanged}">
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

I can update the observable collection data, remove items but not change item background .Any help please.

"Update" : As you can see I don't want to change the color for the whole list box, so I can not bind to a common property like "ItemBackground" instead I must bind to the collection object propert "BackColor"

CKII
  • 1,439
  • 14
  • 26
Emad Ali
  • 447
  • 1
  • 6
  • 11
  • I think it is different. because I'm not trying to change the background color for the whole item list. I need to change the color for each item independently – Emad Ali Nov 12 '17 at 09:50
  • 1
    You need to implement the `INotifyPropertyChanged` in your `Item` class. – Fruchtzwerg Nov 12 '17 at 10:00
  • @Fruchtzwerg is right, you're just missing the `INotifyPropertyChanged` implementation. However, since you're using mvvm, you should reconsider saving the background as a `Brush` inside youre model. In mvvm the model should know nothing about the view, and a `Brush` is very much a part of the view. Consider saving some state instead, and using a converter to change it to the background. – CKII Nov 12 '17 at 10:12
  • @CKII It is a recurring discussion here on SO whether using framework types like Brush in view model violates MVVM or not. Surely, using the type Brush doesn't mean that the "view model knows the view" as you say. It may however avoid reuse for a view that uses a different brush type. But that is of course very unlikely to happen. IMO, using any type that is not derived from UIElement is a perfectly valid view model type, like Color, Brush, Pen, Geometry, ImageSource etc. – Clemens Nov 12 '17 at 10:32
  • @EmadAli As a note, setting `UpdateSourceTrigger=PropertyChanged` on the Background Binding is pointless. It only has an effect in TwoWay or OneWayToSource Bindings. Note also that instead of `new SolidColorBrush(Colors.LightGreen)` you could as well write `Brushes.LightGreen`. – Clemens Nov 12 '17 at 10:36
  • @Clemens I guess it is very much a decision based on personal preferences. But first of all, we're talking here about the Model, not the VM. I understand rules for VM can vary wildly, but for me, the model should remain as clean as possible. Second, I dislike placing anything from the System.Windows.*, Windows.* and Microsoft.* namespaces in the model and VM. Having worked in cross platform dev, I can tell you, it's a pain using these elements there. – CKII Nov 12 '17 at 10:59
  • @CKII Item is a view model class here. It doesn't matter how OP calls it. – Clemens Nov 12 '17 at 11:01
  • Thanks All for your comments. @Fruchtzwerg do I really need to implement INotifyPropertyChange on both item model and my viewmodel ? – Emad Ali Nov 12 '17 at 11:13
  • Typically you should implement it in model and viewmodel. Since no property in your view model changes it would also work without implementing it. – Fruchtzwerg Nov 12 '17 at 17:44

1 Answers1

1

Like suggested in the linked post by @pix your missing the INotifyPropertyChanged interface implementation in for your Item Class. Without INotifyPropertyChanged your UI won't get updates of the changes you make.

public class Item : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Your BackColor property then has to use OnPropertyChanged:

private SolidColorBrush backColor;

public SolidColorBrush BackColor
{
    get { return backColor; }
    set
    {
        backColor = value;
        OnPropertyChanged(nameof(BackColor));
    }
}
pix
  • 1,264
  • 19
  • 32
Andreas
  • 36
  • 3
  • Why do you declare CallerMemberName when you don't use it? That said, if you carefully read the question, you'll realize that OP already has another view model that implements INotifyPropertyChanged. There doesn't seem to be any need to explain how it's implemented. – Clemens Nov 12 '17 at 10:25
  • @Clemens Just for the purpose of showing more clearly that the PropertyChanged is used with the BackColor Property. It is not needed indeed. – Andreas Nov 12 '17 at 10:26
  • I already implemented INotifyPropertyChange on my view model not the item model. Also I think set a property for "backcolor " will affect all listbox items not the current item in my foreach loop. Am I right ? – Emad Ali Nov 12 '17 at 11:15
  • Your not right. The BackgroundColor Property is part of your Item class. Meaning every single Item you Add to your List will have its own Color. Also to make your UI react to changes in the Items Class itself you will have to implement INotifyPropertyChanged. – Andreas Nov 12 '17 at 17:24