Observablecollection Not Noticing When Item in It Changes (Even With Inotifypropertychanged)

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...)

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

Property changes in the observable items in my collection is not recognized by XAML binding the entire item

add a Self property to your model

public Codec Self {
get {
return this;
}
}

public bool IsEnabled
{
get => _isEnabled;
set
{
_isEnabled = value;
OnPropertyChanged();
OnPropertyChanged(Self);
}
}

and then bind to it

AutomationProperties.Name="{Binding Self, Converter={StaticResource CodecPresenter}}">

idea originated from this post on the Xamarin Forums

INotifyPropertyChanged event not firing when Observable Collection changed in WPF in VB.NET

No PropertyChanged event will be raised automatically simply because the type of a property is ObservableCollection. You would have to raise it in the setter:

Set(ByVal value As ObservableCollection(Of Person)) 
_coreInfoData = value
OnPropertyChanged("CoreInfoData")
End Set

INotifyPropertyChanged and ObservableCollection WPF

This is how you typically implement INotifyPropertyChanged:

public class Schedule : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}

private string _monthWeek;
public string MonthWeek
{
get { return _monthWeek; }
set
{
if (value != _monthWeek)
{
_monthWeek = value;
OnPropertyChanged("MonthWeek");
}
}
}

// And so on for other properties...

}

Basically, you just need to trigger the PropertyChanged event every time a property is updated, so every setter must call OnPropertyChanged. Note that you can't do it with auto-implemented properties, since you need to add custom logic in the setter.

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

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 does not refresh even if INotifyProperty interface is implemented

This is your code: (please see the comment also, made by me)

public ObservableCollection<InsertionVM> Insertions // propertyName == Insertions
{
get
{
return _insertions;
}
set
{
_insertions = value;
base.OnPropertyChanged("ChromosomeList"); // What is ChromosomeList??
}
}

Can you see the problem now? Change ChromosomeList to Insertions. Hope some problem at least will be fixed!



Related Topics



Leave a reply



Submit