Notify Observablecollection When Item Changes

Notify ObservableCollection when Item changes

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();
}

Notify item changes in observable collection in WPF/C#

You should implement it yourself, my example of observable collection (and also you need to subscribe and Raise OnPropertyChanged(nameof(Total))) when collection item was changed, or change my implementation of collectionEx to raising collection changed event.

    public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public ObservableCollectionEx(IEnumerable<T> initialData) : base(initialData)
{
Init();
}

public ObservableCollectionEx()
{
Init();
}

private void Init()
{
foreach (T item in Items)
item.PropertyChanged += ItemOnPropertyChanged;

CollectionChanged += FullObservableCollectionCollectionChanged;
}

private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (T item in e.NewItems)
{
if (item != null)
item.PropertyChanged += ItemOnPropertyChanged;
}
}

if (e.OldItems != null)
{
foreach (T item in e.OldItems)
{
if (item != null)
item.PropertyChanged -= ItemOnPropertyChanged;
}
}
}

private void ItemOnPropertyChanged(object sender, PropertyChangedEventArgs e)
=> ItemChanged?.Invoke(sender, e);

public event PropertyChangedEventHandler ItemChanged;
}

How to make an observableCollection notify when an item is updated and not only when is added or removed?

ObservableCollection purpose are to notify the change of a collection, to notify the modification of an object you must implement INotifyPropertyChanged in the object contained in the collection.

ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)

The ContentList's Set method will not get called when you change a value inside the collection, instead you should be looking out for the CollectionChanged event firing.

public class CollectionViewModel : ViewModelBase
{
public ObservableCollection<EntityViewModel> ContentList
{
get { return _contentList; }
}

public CollectionViewModel()
{
_contentList = new ObservableCollection<EntityViewModel>();
_contentList.CollectionChanged += ContentCollectionChanged;
}

public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//This will get called when the collection is changed
}
}

Okay, that's twice today I've been bitten by the MSDN documentation being wrong. In the link I gave you it says:

Occurs when an item is added, removed,
changed, moved, or the entire list is
refreshed.

But it actually doesn't fire when an item is changed. I guess you'll need a more bruteforce method then:

public class CollectionViewModel : ViewModelBase
{
public ObservableCollection<EntityViewModel> ContentList
{
get { return _contentList; }
}

public CollectionViewModel()
{
_contentList = new ObservableCollection<EntityViewModel>();
_contentList.CollectionChanged += ContentCollectionChanged;
}

public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach(EntityViewModel item in e.OldItems)
{
//Removed items
item.PropertyChanged -= EntityViewModelPropertyChanged;
}
}
else if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach(EntityViewModel item in e.NewItems)
{
//Added items
item.PropertyChanged += EntityViewModelPropertyChanged;
}
}
}

public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
//This will get called when the property of an object inside the collection changes
}
}

If you are going to need this a lot you may want to subclass your own ObservableCollection that triggers the CollectionChanged event when a member triggers its PropertyChanged event automatically (like it says it should in the documentation...)

how to get the notification on change in ObservableCollection object

There is only really one way to do this: hook up an event handler on each item as (or before) you add it to the ObservableCollection.

notifyme.Add(new Notify{ PropertyChanged += (o, e) => { do whatever }});

This is because the ObservableCollection is simply a container, each item in it has to be individually hooked up. Of course you could write your own extending class (or extension method) that helps automate this.

How can I notify that a property of an item in an observable collection has changed?

You should be able to tell the View that the collection has changed, and in turn, trigger it to rebind to the entire collection (which would update the View).

If your Model implements INotifyPropertyChanged, the other option would be to have your ViewModelB class listen for changes on it's wrapped Model, and raise property changed events as needed.

ObservableCollection that fires when containing items change

Your TextBlock that bound to HolmList[0].IsOnline didn't update because IsOnline on Holm didn't notify that its value changed.

You can listen to TestSensor's PropertyChanged event in TestSensor and notify IsOnline property change when one of TestSensor's IsOnline property change.

class Holm : ModelBase
{
public Holm(String Name, TestSensor sensor1, TestSensor sensor2)
{
Sensor1 = sensor1;
Sensor2 = sensor2;
this.Name = Name;

Sensor1.PropertyChanged += OnSensorOnlineChanged;
Sensor2.PropertyChanged += OnSensorOnlineChanged;
}

private void OnSensorOnlineChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsOnline")
{
OnPropertyChanged(nameof(IsOnline));
}
}
}

The nameof keyword



Related Topics



Leave a reply



Submit