简体   繁体   中英

Calculated column in a dataGrid bound with a ObservableCollection

I'm building a WPF - MVVM application. I have a dataGrid bound with a ObservableCollection.

In this collection I have a column Quantity,a column Price/MOQ and a column Total that has to be logicaly equal to Quantity * Price = Total.

So each time I add a row and fill Quantity and Price, Total column has to be calculated.

How can I do that?

View

    <DataGrid x:Name="dataGridInvoice" Margin="5" Grid.Row="1" 
                          ItemsSource="{Binding Collection}" 
                          AutoGenerateColumns="False"
                          SelectedItem="{Binding Selected, Mode=TwoWay}" 
                          SelectionMode="Extended" SelectionUnit="FullRow" AddingNewItem="dataGridInvoice_AddingNewItem">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="SuppNb" Binding="{Binding suppInvNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                        <DataGridTextColumn Header="Shop" Binding="{Binding shop, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                        <DataGridTextColumn Header="Date" Binding="{Binding date, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                        <DataGridTextColumn Header="Supplier" Binding="{Binding supplier, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                        <DataGridComboBoxColumn Header="Ref Supplier"
                                                    ItemsSource="{Binding Products, Mode=OneWay, Source={StaticResource supplier}}"
                                                    DisplayMemberPath="refsup" 
                                                    SelectedValueBinding="{Binding refSupp}" 
                                                    SelectedValuePath="refsup"
                                                    Width="*"/>
                        <DataGridTextColumn Header="Description" Binding="{Binding description, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                        <DataGridComboBoxColumn Header="Unit"
                                                    ItemsSource="{Binding Collection, Mode=OneWay, Source={StaticResource unit}}"
                                                    DisplayMemberPath="unit1" 
                                                    SelectedValueBinding="{Binding unit}" 
                                                    SelectedValuePath="idunit"
                                                    Width="*"/>
                        <DataGridTextColumn Header="Quantity" Binding="{Binding quantity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                        <DataGridTextColumn Header="Prix/MOQ" Binding="{Binding unitPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                        <DataGridTextColumn Header="Total Price" Binding="{Binding totalPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                    </DataGrid.Columns>
</DataGrid>

ViewModel

public class InvoiceViewModel : ViewModelBase
{
    public Context ctx = new Context();
    public InvoiceViewModel()
    {
        Get(false);
    }

    private ObservableCollection<Invoice> collection;
    public ObservableCollection<Invoice> Collection
    {
        get
        {
            return collection;
        }
        set
        {
            collection = value;
            OnPropertyChanged("Collection");
        }
    }

    private Invoice _selected;
    public Invoice Selected
    {
        get
        {
            return _selected;
        }
        set
        {
            _selected = value;
            OnPropertyChanged("Selected");
        }
    }

    private void Get(bool loadDataFirst)
    {
        if(loadDataFirst)
            ctx.Invoices.Load();
        Collection = ctx.Invoices.Local;
    }

    private void Save()
    {
        ctx.SaveChanges();
    }

    private void Delete()
    {
        var id = Selected;
        var invoice = (from i in ctx.Invoices
                       where i.idInvoice == id.idInvoice
                       select i).SingleOrDefault();
        Collection.Remove(invoice);
    }

    private Invoice _currentItem;
    public Invoice CurrentItem
    {
        get
        {
            return _currentItem;
        }
        set
        {
            _currentItem = value;
            OnPropertyChanged("CurrentItem");
        }
    }

    #region "Command"

    private ICommand saveCommand;
    private ICommand removeCommand;

    public ICommand SaveCommand
    {
        get
        {
            return saveCommand ?? (saveCommand = new RelayCommand(p => this.Save(), p => this.CanSave()));
        }
    }
    private bool CanSave()
    {
        return true;
    }
    #endregion
}

Model

public partial class Invoice
    {
        public int idInvoice { get; set; }
        public string invNumber { get; set; }
        public string suppInvNumber { get; set; }
        public Nullable<int> supplier { get; set; }
        public Nullable<int> shop { get; set; }
        public Nullable<System.DateTime> date { get; set; }
        public string refSupp { get; set; }
        public string description { get; set; }
        public string unit { get; set; }
        public Nullable<decimal> quantity { get; set; }
        public Nullable<decimal> unitPrice { get; set; }
        public Nullable<decimal> totalPrice { get; set; }

        public virtual foodSupplier foodSupplier { get; set; }
        public virtual shop shop1 { get; set; }
    }

Cantinou,

I see two ways :

  1. Change the Invoice class so that it raises events

    public partial class Invoice : ViewModelBase { // .... private Nullable quantity;

     public Nullable<decimal> Quantity { get { return quantity; } set { quantity = value; base.OnPropertyChanged(); if (quantity.HasValue && unitPrice.HasValue) TotalPrice = quantity * unitPrice; } } private Nullable<decimal> unitPrice; public Nullable<decimal> UnitPrice { get { return unitPrice; } set { unitPrice = value; base.OnPropertyChanged(); if (quantity.HasValue && unitPrice.HasValue) TotalPrice = quantity * unitPrice; } } private Nullable<decimal> totalPrice; public Nullable<decimal> TotalPrice { get { return totalPrice; } set { totalPrice = value; base.OnPropertyChanged(); } } 

    }

  2. Put some code in your GUI to detect end of edition and make product. I think it 's not the responsability of the view to compute prices,... but technically it is possible.

     private void DataGridInvoiceRowEditEnding(object sender, DataGridRowEditEndingEventArgs e) { if (e.EditAction == DataGridEditAction.Commit) { Invoice invoice = e.Row.DataContext as Invoice; // update Invoice object if needed if (invoice != null) { // .... } } } private void DataGridInvoiceCellEditEnding(object sender, DataGridCellEditEndingEventArgs e) { // ... } 

Regards

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM