2015-10-07 134 views
4

我正在学习WPF,所以请裸露我的问题,如果它是非常新手!我有一个Items集合,我想将该集合绑定到一个Grid并将Sum绑定到一个文本框。在线搜索我发现这个类将会引发事件,即使我们对集合对象的属性进行了更改。如何绑定WPF中Observable集合的总和

ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)

但我似乎不能让它在我的代码工作。

这里是我的代码

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)); 
     } 
    } 
} 

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)); 
     } 
    } 
} 

主窗口

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

<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> 

我想测试增加一个项目,当我按一下按钮,并更新项目的网格数量。如果我设置了一个断点并查看Total的值,那么它是正确的,但不知何故它不会在UI上更新。我在这里错过了什么?

回答

6

你想做什么。当集合本身已被更改时,请致电OnPropertyChanged。重新计算总数。目前,Sale类不知道该集合已更新,并且需要更新其Total属性。你可以这样做

的一种方法是,以检查NotifyCollectionChangedEvent这样的:

在你的构造出售():

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

    Items.CollectionChanged += CollectionChanged; 
} 

然后添加事件的处理:

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

如果在集合更改与更新Total属性不同时,您再也无法执行其他任何操作。您可以通过删除事件处理程序和使用lambda表达式,而不是进一步缩短代码:

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

除非你曾经打算明确更新Total自己在Sale类。该setter可以去除:

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

短而甜!谢谢! –

+0

我应该解开事件的地方?或者让GC完成这项工作? –

1

在Sales.cs补充:

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

在MainWindow.xaml。CS呼叫:

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

而不是

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

这将更新总。

+0

感谢您投票,但@JBond提供了更好的解决方案。我的解决方案也适用于简单的List <>等,但由于您使用的是ObservableCollection <>,因此您可以使用这些好处,例如CollectionChanged事件。 :) – KAI