Bind to total of an items field in an ObservableCollection and update when values change
Clash Royale CLAN TAG#URR8PPP
Bind to total of an items field in an ObservableCollection and update when values change
I have an ObservableCollection that populates a datagrid in WPF. I need to bind to the total of the "Hours" column, and have that total update when a value in the "Hours" column is changed. I can achieve this by listening to the "LostFocus" event and running a function, but would like to try my hand at binding.
The issue I am running into, is the NotifyPropertyChanged event will not fire when an items property in the collection is changed.
The sortie class NotifyPropertyChanged will fire, but the collection doesn't interpret that as its own property changing. How can I listen to the sortie PropertyChanged from the collection in the missions class?
My Models
public class Mission : INotifyPropertyChanged
private ObservableCollection<Sortie> sorties;
public ObservableCollection<Sortie> Sorties
get return this.sorties;
set
if (this.sorties != value)
this.sorties = value;
this.NotifyPropertyChanged("Sorties");
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
public class Sortie : INotifyPropertyChanged
private double hours;
public double Hours
get return this.hours;
set
if (this.hours != value)
this.hours = value;
this.NotifyPropertyChanged("Hours");
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
I didn't bother posting my XAML or View Model, as I am confident I can solve the issue once I learn how to trigger a PropertyChanged event for the collection and I wanted to spare you having to read through massive amounts of code. If you believe it is needed however, let me know.
2 Answers
2
Write a readonly property in the parent viewmodel that calculates the value.
public double SortieHours => Sorties.Sum(x => x.Hours);
Parent viewmodel handles PropertyChanged
on each item in Sorties
, and CollectionChanged
on Sorties
. In CollectionChanged
on Sorties
, you have to add/remove PropertyChanged
handlers from Sortie
instances as they're added and removed. When you get a new Sorties
collection (you might want to make that setter private for this reason), you need to toss out all the old handlers and add new ones.
PropertyChanged
Sorties
CollectionChanged
Sorties
CollectionChanged
Sorties
PropertyChanged
Sortie
Sorties
Now, whenever a Sortie
is added or removed, or its Hours
changes, or somebody hands you a new Sorties
collection, raise PropertyChanged
:
Sortie
Hours
Sorties
PropertyChanged
OnPropertyChanged(nameof(SortieHours));
And bind that property to whatever you like in the XAML.
This looks horrible (because it is), but what else are you going to do?
A lot of people would advise you to give Sortie
an HoursChanged
event. PropertyChanged
is annoying for this type of case because it can get raised for multiple different properties and you have to check which one. And it's a magic string thing.
Sortie
HoursChanged
PropertyChanged
Above is C#6. For C#5,
public double SortieHours get return Sorties.Sum(x => x.Hours);
OnPropertyChanged("SortieHours");
Ugh....so ugly, but can't deny that it works. Thank you.
– Tronald
Aug 31 '16 at 20:05
not sure why this is considered ugly, seems rational to me. +1
– NappingRabbit
Aug 27 at 11:38
@NappingRabbit It’s ugly because there are so many events and handlers involved in keeping a single value up to date. It’s rational, certainly: It’s your only option, and it works. But it’s not pretty.
– Ed Plunkett
Aug 27 at 11:54
I found this link to be a big help. It creates a base class for ObservableCollections to "AutoMagicly" add the PropertyChanged events of the collection items to the CollectionChanged event.
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Multidupe. OC doesn't listen to INPC of its children. You have to manage this.
– Will
Aug 31 '16 at 19:56