ostomac
ostomac

Reputation: 35

WPF - Notify ViewModel when object property is changed

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

Answers (2)

MarcSanchez
MarcSanchez

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

hoodaticus
hoodaticus

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

Related Questions