I found on this link
ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)
some techniques to notify a Observablecollection that an item has changed. the TrulyObservableCollection in this link seems to be what i'm looking for.
public class TrulyObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged { public TrulyObservableCollection() : base() { CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged); } void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) { foreach (Object item in e.NewItems) { (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged); } } if (e.OldItems != null) { foreach (Object item in e.OldItems) { (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged); } } } void item_PropertyChanged(object sender, PropertyChangedEventArgs e) { NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); OnCollectionChanged(a); } }
But when I try to use it, I don't get notifications on the collection. I'm not sure how to correctly implement this in my C# Code:
XAML :
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding MyItemsSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> <DataGrid.Columns> <DataGridCheckBoxColumn Binding="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> </DataGrid.Columns> </DataGrid>
ViewModel :
public class MyViewModel : ViewModelBase { private TrulyObservableCollection<MyType> myItemsSource; public TrulyObservableCollection<MyType> MyItemsSource { get { return myItemsSource; } set { myItemsSource = value; // Code to trig on item change... RaisePropertyChangedEvent("MyItemsSource"); } } public MyViewModel() { MyItemsSource = new TrulyObservableCollection<MyType>() { new MyType() { MyProperty = false }, new MyType() { MyProperty = true }, new MyType() { MyProperty = false } }; } } public class MyType : ViewModelBase { private bool myProperty; public bool MyProperty { get { return myProperty; } set { myProperty = value; RaisePropertyChangedEvent("MyProperty"); } } } public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void RaisePropertyChangedEvent(string propertyName) { if (PropertyChanged != null) { PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName); PropertyChanged(this, e); } } }
When i run the program, i have the 3 checkbox to false, true, false as in the property initialisation. but when i change the state of one of the ckeckbox, the program go through item_PropertyChanged but never in MyItemsSource Property code.
Remarks. The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed. For example, consider a Person object with a property called FirstName .
The true difference is rather straightforward:ObservableCollection implements INotifyCollectionChanged which provides notification when the collection is changed (you guessed ^^) It allows the binding engine to update the UI when the ObservableCollection is updated. However, BindingList implements IBindingList.
An ObservableCollection is a dynamic collection of objects of a given type. Objects can be added, removed or be updated with an automatic notification of actions. When an object is added to or removed from an observable collection, the UI is automatically updated.
The spot you have commented as // Code to trig on item change...
will only trigger when the collection object gets changed, such as when it gets set to a new object, or set to null.
With your current implementation of TrulyObservableCollection, to handle the property changed events of your collection, register something to the CollectionChanged
event of MyItemsSource
public MyViewModel() { MyItemsSource = new TrulyObservableCollection<MyType>(); MyItemsSource.CollectionChanged += MyItemsSource_CollectionChanged; MyItemsSource.Add(new MyType() { MyProperty = false }); MyItemsSource.Add(new MyType() { MyProperty = true}); MyItemsSource.Add(new MyType() { MyProperty = false }); } void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { // Handle here }
Personally I really don't like this implementation. You are raising a CollectionChanged
event that says the entire collection has been reset, anytime a property changes. Sure it'll make the UI update anytime an item in the collection changes, but I see that being bad on performance, and it doesn't seem to have a way to identify what property changed, which is one of the key pieces of information I usually need when doing something on PropertyChanged
.
I prefer using a regular ObservableCollection
and just hooking up the PropertyChanged
events to it's items on CollectionChanged
. Providing your UI is bound correctly to the items in the ObservableCollection
, you shouldn't need to tell the UI to update when a property on an item in the collection changes.
public MyViewModel() { MyItemsSource = new ObservableCollection<MyType>(); MyItemsSource.CollectionChanged += MyItemsSource_CollectionChanged; MyItemsSource.Add(new MyType() { MyProperty = false }); MyItemsSource.Add(new MyType() { MyProperty = true}); MyItemsSource.Add(new MyType() { MyProperty = false }); } void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.NewItems != null) foreach(MyType item in e.NewItems) item.PropertyChanged += MyType_PropertyChanged; if (e.OldItems != null) foreach(MyType item in e.OldItems) item.PropertyChanged -= MyType_PropertyChanged; } void MyType_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "MyProperty") DoWork(); }
I solved this case by using static Action
public class CatalogoModel { private String _Id; private String _Descripcion; private Boolean _IsChecked; public String Id { get { return _Id; } set { _Id = value; } } public String Descripcion { get { return _Descripcion; } set { _Descripcion = value; } } public Boolean IsChecked { get { return _IsChecked; } set { _IsChecked = value; NotifyPropertyChanged("IsChecked"); OnItemChecked.Invoke(); } } public static Action OnItemChecked; } public class ReglaViewModel : ViewModelBase { private ObservableCollection<CatalogoModel> _origenes; CatalogoModel.OnItemChecked = () => { var x = Origenes.Count; //Entra cada vez que cambia algo en _origenes }; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With