How to update a dynamic field using ObservableCollection on a Silverlight datagrid
This problem could be bad class design or ignorance - please bear with me:
I have 2 classes - Chip (which implements INotifyPropertyChanged and represents a single poker chip) and ChipSet, which implements INotifyPropertyChanged and has an ObservableCollection of Chip.
I have a Datagrid which is bound to the Chip ObservableCollection and a Textblock which is bound to ChipSet.
ie.开发者_C百科 gridChips.ItemsSource = chipset.Chips;
The Chip class has 3 properties (for simplicity) - NumberPerPlayer, ChipValue and TotalValuePerPlayer. TotalValuePerPlayer does not have a property set or associated private member variable like the other 2 - it is dynamically based off the product of ChipValue and NumberPerPlayer.
The grid binds to all 3 of these values and shows these 3 columns. Only the first 2 are editable and the 3rd one updates as the other 2 changes.
This works fine so far - I found that in order to get the TotalValuePerPlayer column to update if either of the other columns updated I had to add this field to PropertyChangedEventArgs (see code below).
My first question- Is this the best way of updating bound class fields that are based off other fields and do not change in the UI (you cannot edit TotalValuePerPlayer directly).
public int NumberPerPlayer
{
get { return numberPerPlayer; }
set
{
if (numberPerPlayer != value)
{
numberPerPlayer = value;
OnPropertyChanged("NumberPerPlayer");
OnPropertyChanged("TotalValuePerPlayer");
}
}
}
public decimal ChipValue
{
get { return chipValue; }
set
{
if (chipValue != value)
{
chipValue = value;
//all columns that are based on this need to be updated
OnPropertyChanged("ChipValue");
OnPropertyChanged("TotalValuePerPlayer");
}
}
public decimal TotalValuePerPlayer { get { return chipValue * numberPerPlayer; } }
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
My 2nd, main question is this: I then have a label which shows the total of all the TotalValuePerPlayer totals (stupidly called TotalTotalValuePerPlayer). I put this in the ChipSet class like this (it iterates through the ObservableCollection and sums the totals):
1 public decimal TotalTotalValuePerPlayer
2 {
3 get {
4 decimal totalTotalValuePerPlayer = 0;
5 foreach (Chip chip in chips)
6 {
7 totalTotalValuePerPlayer += chip.TotalValuePerPlayer;
8 }
9 return totalTotalValuePerPlayer;
10 }
11 }
So - the problem is that when either of the 2 columns (NumberPerPlayer or ChipValue) this field is based on in the UI changes, it does not update.
How do I tell the parent class - ChipSet, which has the TotalTotalValuePerPlayer member to be updated when one of its children class (Chip) members in it's ObservableCollection is updated?
If the TotalTotalValuePerPlayer was in the Chip class I could just notify it when the fields it was based off changed, but it is in the class above it?
Thanks for any advice!
Rodney
Hi there I believe you are going around this the correct way you just need to go a step further. Here are how would expect the classes to look:
Chip
public class Chip : INotifyPropertyChanged
{
private int numberPerPlayer;
public int NumberPerPlayer
{
get { return numberPerPlayer; }
set
{
if (numberPerPlayer != value)
{
numberPerPlayer = value;
OnPropertyChanged("NumberPerPlayer");
OnPropertyChanged("TotalValuePerPlayer");
}
}
}
private decimal chipValue;
public decimal ChipValue
{
get { return chipValue; }
set
{
if (chipValue != value)
{
chipValue = value;
//all columns that are based on this need to be updated
OnPropertyChanged("ChipValue");
OnPropertyChanged("TotalValuePerPlayer");
}
}
}
public decimal TotalValuePerPlayer
{
get
{
return chipValue * numberPerPlayer;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ChipSet
public class ChipSet : INotifyPropertyChanged
{
public ChipSet()
{
foreach (var chip in Chips)
{
chip.PropertyChanged += (s, e) => { OnPropertyChanged("TotalTotalValuePerPlayer"); };
}
}
public ObservableCollection<Chip> Chips { get; set; }
public decimal TotalTotalValuePerPlayer
{
get
{
return Chips.Sum(x => x.TotalValuePerPlayer);
}
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
I have not tested this fully but it should point you in the right direction. Hope it helps.
精彩评论