Search code examples
c#wpfmvvmwpfdatagrid

C# Changing other values on everytime something is changed using mvvm


I have a DataGrid that is bound to an ObservableCollection<Item>. When I change the Quantity of an Item I would like to automatically change the total of the item. Which is Quantity*Cost=Total

<DataGrid ItemsSource="{Binding Invoices.Items}" AutoGenerateColumns="False">
    <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
    <DataGridTextColumn Header="Quantity" Binding="{Binding Quantity}" />
    <DataGridTextColumn Header="Cost" Binding="{Binding Cost}" />
    <DataGridTextColumn Header="Total" Binding="{Binding Total}" />
</DataGrid>

The ViewModel is vary simple"

public class ViewModel:BaseClass
{
    public ViewModel()
    {
        FillInvoice();
    }

    private Invoice _invoice;
    public Invoice Invoice
    {
        get { return _invoice; }
        set
        {
            if (_invoice!=value)
            {
                _invoices = value;
                OnPropertyChanged();
            }
        }
    }

    private void FillInvoice()
    {
        var customer = new Customer() {Id=1,Name = "James"};
        var invoice = new Invoice() {Customer = customer, Id = 1,CustomerId = 1};
        var item = new Item() {Cost = Convert.ToDecimal(12.50),Id = 1,Name = "Item"};
        for (int i = 0; i < 10; i++)
        {
            invoice.Items.Add(item);
        }
        Invoices = invoice;
    }
}

The Invoice Look like:

public Invoices()
{
    Items=new ObservableCollection<Item>();
}
public int Id { get; set; }
public int CustomerId { get; set; }
public Customer Customer { get; set; }
public ObservableCollection<Item> Items { get; set; }

My Item Looks like:

public class Item:BaseClass
{
    private string _name;
    private decimal _cost;
    public int Id { get; set; }
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name!=value)
            {
                _name = value;
                OnPropertyChanged();
            }
        }
    }

    private int _quantity;
    public int Quantity
    {
        get { return _quantity; }
        set
        {
            if (_quantity!=value)
            {
                _quantity = value;
                OnPropertyChanged();
            }
        }
    }

    public decimal Cost
    {
        get { return _cost; }
        set
        {
            if (_cost!=value)
            {
                _cost = value;
                OnPropertyChanged();
            }
        }
    }

    private decimal _total;

    public decimal Total
    {
        get { return _total; }
        set
        {
            if (_total != value)
            {
                _total = value;
                OnPropertyChanged();
            }

        }
    }

}

What I was thinking was adding an eventhandler to the Quantity item that will calculate the total for me but I am not sure how to do that I have Tried adding.

public ViewModel(){
    Invoice.Items.Quantity.PropertyChanged += (s,e)
    {
        Total = Cost*Quantity
    }
}



public Item()
{
    Quantity.PropertyChanged += (s,e)
    {
        Total = Cost*Quantity
    }
}

but it doesn't compile on them.


Solution

  • You could just implement Total as a calculated property, if it is always equal to Cost*Quantity, as there is no point in storing redundant data :

    public decimal Total
    {
        get { return Cost * Quantity; }
    }
    

    This should then just work, assuming OnPropertyChanged() with no parameters fires a generic/null property change event which will cause all subscribed properties to be rechecked.