Reputation: 35
I'm new to WPF and MVVM (and programming in general), so sorry in advance for noobish question, but i really want to make this work in MVVM
I have a ObservableCollection class and ViewModel where i use it, now i want to calculate OreMineTotal and OreTransportTotal in ViewModel every time when i change "Role" in my UI (two way binding).
This works now but only when I add or remove item from ObservableCollection.
1st queston Why is setter for Players ObservableCollection in ViewModel not firing when i change Player role in UI.
2nd How to solve this in MVVM, i would like to know how to intercept/subscribe to RaisePropertyChanged("Role") that is in Player class from ViewModel
In winforms i would handle it in (mouse click or whatever) event where i change player role, but i want to do it MVVM style
namespace MiningCalc.Model
{
public class Player : INotifyPropertyChanged
{
public Player()
{
items = new ObservableCollection<MinedItems>();
}
private string name;
private string mass;
private int fc;
private int boost;
private int log;
private int role;
private ObservableCollection<MinedItems> items;
public ObservableCollection<MinedItems> Items
{
get
{
return items;
}
set
{
if (items != value)
{
items = value;
RaisePropertyChanged("Items");
}
}
}
public string Name
{
get
{
return name;
}
set
{
if (name != value)
{
name = value;
RaisePropertyChanged("Name");
}
}
}
...... other variables .....
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
}
}
And ViewModel
namespace MiningCalc.ViewModel
{
class ViewModelPlayer : INotifyPropertyChanged
{
private decimal oreMineTotal;
private decimal oreTransportTotal;
private ObservableCollection<Player> players;
public ObservableCollection<Player> Players
{
get
{
return players;
}
set
{
players = value;
OnPropertyChanged("Players");
OnPropertyChanged("OreMineTotal"); //not working
OnPropertyChanged("OreTransportTotal"); // not working
}
}
public ViewModelPlayer()
{
players = new ObservableCollection<Player>();
players.CollectionChanged += OnCollectionChanged;
LoadLogCommand = new RelayCommand(LoadLog, LoadLog_CanExecute);
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//System.Windows.MessageBox.Show("Firing");
OnPropertyChanged("OreMineTotal");
OnPropertyChanged("OreTransportTotal");
}
public decimal OreMineTotal
{
get
{
oreMineTotal = Players.Where(x => x.Role == 0).Sum(a => decimal.Parse(a.Mass, NumberStyles.Any));
return oreMineTotal;
}
set
{
oreMineTotal = value;
OnPropertyChanged("OreMineTotal");
}
}
public decimal OreTransportTotal
{
get
{
oreTransportTotal = Players.Where(x => x.Role == 1).Sum(a => decimal.Parse(a.Mass, NumberStyles.Any));
return oreTransportTotal;
}
set
{
oreTransportTotal = value;
OnPropertyChanged("OreTransportTotal");
}
}
...........
Upvotes: 1
Views: 4260
Reputation: 101
Take a look to Dependency Properties Tutorial in C#. Very useful for your propose.
Allows you to bind models and views in a bidirectional way.
Upvotes: -1
Reputation: 3880
Whenever an item is added to your ObservableCollection
, you need to add a PropertyChanged
event handler to that item and use it to update your totals.
Whenever an item is removed from your ObservableCollection
, you need to remove that handler.
Whenever an item is replaced in your ObservableCollection
, you need to remove the handler from the old item and add a handler to the new item.
This is usually implemented inside the CollectionChanged
handler using a switch statement on the change type enum of the NotifyCollectionChangedEventArgs
.
At the moment you are only tracking changes to the collection itself. You need to also monitor changes to the items :)
Other than that, you have no MVVM problem here. Your code is, other than the above, expert-level MVVM. There is no further MVVM way to enhance your code.
Upvotes: 2