ObservableCollection.CollectionChanged 未触发

Posted

技术标签:

【中文标题】ObservableCollection.CollectionChanged 未触发【英文标题】:ObservableCollection.CollectionChanged not firing 【发布时间】:2013-03-19 20:33:22 【问题描述】:

我有如下界面:

当一个项目被添加到DataGrid 中时,Total column 将根据(价格 * 数量)更新,并且总数 TextBox 也将具有添加的所有行的总数。

但是,当我更改行的数量时,Total column 会更新,但总数 TextBox 不会。

这是我的代码,在此先感谢。

 public partial class pgCheckout : Page 

    ObservableCollection<SaleItem> items = new ObservableCollection<SaleItem>();

    public pgCheckout() 
        InitializeComponent();
        dgItems.ItemsSource = items;
        dgItems.Loaded += SetMinWidths;
        items.CollectionChanged += setTotal;
    

    public void setTotal(object source, EventArgs e) 
        decimal total = 0;
        foreach(SaleItem i in items) 
            total += i.Total;
        

        txtTotal.Text = total.ToString();
    


    public void SetMinWidths(object source, EventArgs e) 
        foreach (var column in dgItems.Columns) 
            if (column.DisplayIndex != 0) 
                column.MinWidth = column.ActualWidth;
                column.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
            
        
    

    private void btnRemove_Click(object sender, RoutedEventArgs e) 
        items.RemoveAt(dgItems.SelectedIndex);
    

    private void btnAdd_Click(object sender, RoutedEventArgs e) 
        bool exist = false;
        foreach (SaleItem i in items) 
            if (i.ItemID.Equals(txtItemID.Text))
                exist = true;
        

        if (exist) 
            lblErr.Content = "Item already exist";
            txtItemID.Text = "";
        

        else 

            using (var db = new PoSEntities()) 
                var query = from i in db.Items
                            where i.ItemID.Equals(txtItemID.Text.Trim())
                            select i;
                var itm = query.FirstOrDefault();
                if (itm == null) 
                    lblErr.Content = "Invalid Item";
                    txtItemID.Text = "";
                
                else 
                    txtItemID.Text = "";
                    lblErr.Content = "";
                    items.Add(new SaleItem() 
                        Num = items.Count + 1,
                        ItemID = itm.ItemID,
                        Name = itm.Name,
                        Price = decimal.Round(itm.Price, 2, MidpointRounding.AwayFromZero),
                        Quantity = 1,
                    );
                
            
        
    

    private void txtItemID_KeyUp(object sender, KeyEventArgs e) 
        if (e.Key == System.Windows.Input.Key.Enter) 
            btnAdd_Click(txtItemID, e);
        
    


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

【问题讨论】:

你能展示SaleItem类吗? SaleItem 类包含在代码底部附近。 【参考方案1】:
 ObservableCollection<SaleItem> items = new ObservableCollection<SaleItem>();

必须是属性

改成

public ObservableCollection<SaleItem> items get;set;

在构造函数中做新的

如果不存在,则让 get 函数创建新对象

你必须有公共的 getter/setter 才能使用绑定

【讨论】:

【参考方案2】:

ObservableCollection.CollectionChanged 从集合中添加或删除某些内容而不是正在更新的单个成员时触发。

...
else 

    txtItemID.Text = "";
    lblErr.Content = "";
    SaleItem newItem = new SaleItem() 
                    Num = items.Count + 1,
                    ItemID = itm.ItemID,
                    Name = itm.Name,
                    Price = decimal.Round(itm.Price, 2, MidpointRounding.AwayFromZero),
                    Quantity = 1 ;
     newItem.PropertyChanged += 
             new PropertyChangedEventHandler(newSaleItem_PropertyChanged);

    items.Add(newItem);
 
 ...

这是newSaleItem_PropertyChanged

void newSaleItem_PropertyChanged(object sender, PropertyChangedEventArgs e)

    setTotal(null, null);

【讨论】:

我明白了。我应该如何解决这个问题? 如果您的SaleItem 实现了INotifyPropertyChanged,那么您可以为每个SaleItem 使用PropertyChanged 事件。我要编辑我的帖子。【参考方案3】:

您的SaleItem 必须实现INotifyPropertyChanged 然后您将拥有PropertyChanged 事件并且您可以订阅它。使用 INotifyPropertyChanged 将有利于绑定。

【讨论】:

以上是关于ObservableCollection.CollectionChanged 未触发的主要内容,如果未能解决你的问题,请参考以下文章