I am not sure what you are trying to do however I'll show you how to handle each item in the
ObservableCollection
.
The Item class needs to implement the
INotifyPropertyChanged Interface (System.ComponentModel)[
^]. Microsoft provide a sample:
How to: Implement Property Change Notification - WPF .NET Framework | Microsoft Learn[
^]. They also have a lib to make implementation easy:
Introduction to the MVVM Toolkit - Community Toolkits for .NET | Microsoft Learn[
^]. Each item class that requires change tracking needs to implement the
ObservableObject[
^].
To keep my sample not reliant on the Community Toolkit, I've implemented my own
ObservableObject
that can be replace with the toolkit version:
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class ObservableObject : INotifyPropertyChanged
{
protected bool Set<TValue>
(ref TValue field, TValue newValue,
[CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<TValue>
.Default.Equals(field, newValue)) return false;
field = newValue;
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(
[CallerMemberName] string? propertyName = null)
=> PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
Now we update the
Person
class from my
previous solution[
^]:
public class Person : ObservableObject
{
private string name;
private string country;
public string Name
{
get => name;
set => Set(ref name, value);
}
public string Country
{
get => country;
set => Set(ref country, value);
}
}
Now we can update the
MainWindow.cs class from my
previous solution[
^]:
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Timers;
using System.Windows;
namespace WpfCollectionViewSourceGrouping;
public partial class MainWindow : IDisposable
{
public ObservableCollection<Person> People { get; set; } = new();
private static List<string> countries = new()
{
"Australia",
"Canada",
"United Kingdom",
"United States"
};
private Random rand = new();
private System.Timers.Timer timer;
public MainWindow()
{
InitializeComponent();
People.CollectionChanged += OnPeopleCollectionChanged;
for (int i = 0; i < 20; i++)
{
People.Add(new(){ Name = $"Person {i}", Country = countries[rand.Next(0, countries.Count)]});
}
DataContext = this;
this.Closing += OnClosing;
timer = new System.Timers.Timer(1000);
timer.Elapsed += OnTimerTick;
timer.AutoReset = true;
timer.Enabled = true;
}
private void OnTimerTick(object? sender, ElapsedEventArgs e)
{
Person person = People[rand.Next(0, People.Count)];
string countryName = person.Country;
while (countryName == person.Country)
{
person.Country = countries[rand.Next(0, countries.Count)];
}
}
private void OnPeopleCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (e.NewItems is null)
return;
foreach (Person person in e.NewItems)
{
Debug.WriteLine($"Listening to: {person.Name}");
person.PropertyChanged += OnPersonPropertyChanged;
}
break;
case NotifyCollectionChangedAction.Remove:
if (e.OldItems is null)
return;
foreach (Person person in e.OldItems)
{
Debug.WriteLine($"Unhooking: {person.Name}");
person.PropertyChanged -= OnPersonPropertyChanged;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private void OnPersonPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
Person? person = sender as Person;
Debug.WriteLine($"{person.Name}'s {e.PropertyName} has changed to {person!.Country}");
}
private void OnClosing(object? sender, CancelEventArgs e)
{
this.Dispose();
}
public void Dispose()
{
foreach (Person person in People)
{
Debug.WriteLine($"Unhooking: {person.Name}");
person.PropertyChanged -= OnPersonPropertyChanged;
}
People.CollectionChanged -= OnPeopleCollectionChanged;
timer.Stop();
timer.Elapsed -= OnTimerTick;
timer.Dispose();
this.Closing -= OnClosing;
}
}
The above code shows:
* How to implement property changed notifications
INotifyProperyChanged event
* How start & stop listening using the
CollectionChanged
event when items are added and removed from the
ObservableCollection
.
* sample code to fire property changed events and how to handle them.
* how to avoid memory leaks
Now run the app. What you will see in the
Output Window (debug output):
Listening to: Person 0
Listening to: Person 1
Listening to: Person 2
Listening to: Person 3
Listening to: Person 4
Listening to: Person 5
Listening to: Person 6
Listening to: Person 7
Listening to: Person 8
Listening to: Person 9
Listening to: Person 10
Listening to: Person 11
Listening to: Person 12
Listening to: Person 13
Listening to: Person 14
Listening to: Person 15
Listening to: Person 16
Listening to: Person 17
Listening to: Person 18
Listening to: Person 19
while the app is running:
Person 13's Country has changed to United Kingdom
Person 15's Country has changed to United States
Person 8's Country has changed to Australia
Person 6's Country has changed to Australia
Person 11's Country has changed to Canada
Person 2's Country has changed to Australia
Person 17's Country has changed to Canada
Person 2's Country has changed to United States
Person 14's Country has changed to Canada
and when you close the window:
Unhooking: Person 0
Unhooking: Person 1
Unhooking: Person 2
Unhooking: Person 3
Unhooking: Person 4
Unhooking: Person 5
Unhooking: Person 6
Unhooking: Person 7
Unhooking: Person 8
Unhooking: Person 9
Unhooking: Person 10
Unhooking: Person 11
Unhooking: Person 12
Unhooking: Person 13
Unhooking: Person 14
Unhooking: Person 15
Unhooking: Person 16
Unhooking: Person 17
Unhooking: Person 18
Unhooking: Person 19
Again, If you do your research with Google search, all of the information is tere for you, you just need to make the effort and look.
For a
DataGrid
, if you use an
ObservableCollection
and implement the
INotifyPropertyChanged
for the item class, as above, the
DataGrid
will handle the events for both the
ObservableCollection
and all items in the collection that implement the
INotifyPropertyChanged
as demonstrated above.
If we peek at the
ObservableCollection
we can see the event implemented:
public class ObservableCollection<T> :
Collection<T>,
INotifyCollectionChanged,
INotifyPropertyChanged
Enjoy!