简体   繁体   English

如何在WPF中绑定可观察集合的总和

[英]How to Bind Sum of Observable collection in WPF

I am learning WPF so please bare my question if it is very novice! 我正在学习WPF,所以如果是新手,请回答我的问题! I have a collection of Items and I want to bind that collection to a Grid and bind the Sum to a textbox. 我有一个Items集合,我想将该集合绑定到Grid并将Sum绑定到文本框。 Searching online I found this class that will raise event even when we make change to properties of the collection object. 在线搜索时,我发现该类将引发事件,即使我们更改集合对象的属性也是如此。

ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged) ObservableCollection不会注意到其中的Item更改的时间(即使使用INotifyPropertyChanged)

But I can't seem to make it work in my code. 但是我似乎无法使其在我的代码中起作用。

Here is my code 这是我的代码

SaleItem SaleItem

public class SaleItem : INotifyPropertyChanged
{
    public int Num { get; set; }
    public string ItemID { get; set; }
    public string Name { get; set; }

    private decimal price;
    public decimal Price
    {
        get { return price; }
        set
        {
            this.price = value;
            OnPropertyChanged("Total");
        }
    }
    public int quantity;
    public int Quantity
    {
        get { return quantity; }
        set
        {
            this.quantity = value;
            OnPropertyChanged("Total");
        }
    }

    public decimal Total
    {
        get { return decimal.Round(Price * Quantity, 2, MidpointRounding.AwayFromZero);}
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Sale 特卖

public class Sale : INotifyPropertyChanged 
{
    private Decimal _total;
    public TrulyObservableCollection<SaleItem> Items { get; set; }

    public Sale()
    {
        Items = new TrulyObservableCollection<SaleItem>();
        Items.Add(new SaleItem { ItemID = "1", Name = "Product 1", Price = 10, Quantity = 1 });
        Items.Add(new SaleItem { ItemID = "2", Name = "Product 2", Price = 10, Quantity = 1 });
        Items.Add(new SaleItem { ItemID = "3", Name = "Product 3", Price = 10, Quantity = 1 });

    }

    public Decimal Total
    {
        get
        { 
            return Items.Sum(x => x.Total);
        }
        set
        {
            _total = value;
            OnPropertyChanged("Total");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

MainWindow 主窗口

public partial class MainWindow : Window
{
    public Sale Model { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        Model = new Sale();
        this.DataContext = Model;            
    }



    private void btnQuantity_Click(object sender, RoutedEventArgs e)
    {
        Model.Items.Add(new SaleItem { ItemID = "2", Name = "Product 2", Price = 10, Quantity = 1 });

    }
}

XAML XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local ="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">

<Window.DataContext>
    <local:Sale />
</Window.DataContext>

<Grid>
    <StackPanel>
        <DataGrid x:Name="grdItems" ItemsSource="{Binding Items}"></DataGrid>
        <TextBlock x:Name="txtTotal" Text="{Binding Total}"/>
        <Button x:Name="btnQuantity" Content="Update" Click="btnQuantity_Click"/>
    </StackPanel>
</Grid>

I am trying to test adding an item when I click on the button and also updating the quantity of the Item in the grid. 我尝试在单击按钮时测试添加项目,并更新网格中项目的数量。 If I set a break point and see the value of Total, then it is correct but somehow it is not updating on the UI. 如果我设置了一个断点并看到Total的值,那么它是正确的,但是以某种方式它不会在UI上更新。 What am I missing here? 我在这里想念什么?

What you want to do. 你想做什么。 Is to call OnPropertyChanged when the collection itself has been changed. 是在集合本身已更改时调用OnPropertyChanged To recalculate the total. 重新计算总数。 At the moment, the Sale class has no idea that the collection has been updated and that it needs to update its Total property. 目前, Sale类不知道该集合已更新,并且需要更新其Total属性。

One way you can do this is to check for the NotifyCollectionChangedEvent like this: 一种执行此操作的方法是检查NotifyCollectionChangedEvent如下所示:

In your constructor for Sale(): 在您的Sale()构造函数中:

public Sale()
{
 //Instantiate your collection and add items

  Items.CollectionChanged += CollectionChanged;
}

Then add the handler for the event: 然后添加事件的处理程序:

public void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
  OnPropertyChanged("Total");
}

If you're never going to do anything else when the collection changes apart from update the Total property. 如果您不打算做其他任何事情,则除了更新Total属性之外,集合还应进行更改。 You can shorten the code further by removing the event handler and using a lambda expression instead: 您可以通过删除事件处理程序并使用lambda表达式来进一步缩短代码:

Items.CollectionChanged += (s,e) => OnPropertyChanged("Total");

Unless you're ever planning on explicitly updating the Total yourself in the Sale class. 除非您打算在Sale类中自己明确更新Total The setter can be removed: setter可以删除:

public Decimal Total
{
  get
  {
    return Items.Sum(x => x.Total);
  }
}

In the Sales.cs add: 在Sales.cs中添加:

public void AddItem(SaleItem item)
    {
        Items.Add(item);
        OnPropertyChanged("Total");
    }

In MainWindow.xaml.cs call: 在MainWindow.xaml.cs中调用:

Model.AddItem(new SaleItem { ItemID = "2", Name = "Product 2", Price = 10, Quantity = 1 });

Instead of 代替

Model.Items.Add(new SaleItem { ItemID = "2", Name = "Product 2", Price = 10, Quantity = 1 });

This will update the Total. 这将更新总计。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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