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
How to Parse a Json String That Would Cause Illegal C# Identifiers
How to Get Started With Developing Internet Explorer Extensions
Post an HTML Table to Ado.Net Datatable
What Do 'Statically Linked' and 'Dynamically Linked' Mean
How to Deserialize Json With C#
Why Does C# Not Provide the C++ Style 'Friend' Keyword
Why Are Mutable Structs "Evil"
How to Create an Excel (.Xls and .Xlsx) File in C# Without Installing Microsoft Office
Using C# Regular Expressions to Remove HTML Tags
How to Handle Both a Single Item and an Array For the Same Property Using Json.Net
Html Agility Pack - Parsing Tables
Encrypt and Decrypt a String in C#
Does Page Reload Ever Cause Post
Convert Utc/Gmt Time to Local Time
How to Add a Timeout to Console.Readline()
There Is Already an Open Datareader Associated With This Command Which Must Be Closed First