c# - 在 ObservableCollection 上触发 InotifyPropertyChanged/CollectionChanged

标签 c# wpf observablecollection

我已经尝试查看与此相关的其他主题,但我还没有找到我的问题的有效实现。基本上,我有一个名为“FruitBasket”的 ObservableCollection,其中包含不同种类的水果。 FruitBasket 本身包含每种经过的水果类型的 ObservableCollections,以便它们可以用作 ListViews 的 ItemSources(用它们的名称表示) AppleContainer”和“OrangeContainer”),每个都显示一种水果。因为水果类本身实现了 INotifyPropertyChanged,所以修改它们的值会很好地触发 ListView 控件的更新,但是,FruitBasket 有一个从集合中所有其他水果的权重派生的“TotalWeight”属性。我希望“TotalWeight”更新 UI 中的 Label 控件,而无需刷新 UI。触发有关实际 ObservableCollection 本身(而不仅仅是其组成成员)的属性更改的通知更加困难,而且到目前为止我还没有找到任何有效的解决方案(或者我已经正确实现) .

public class FruitBasket : ObservableCollection<IFruit>
{
    private decimal _totalWeight;

    public FruitBasket()
    {
        this.Add(new OrangeContainer(this));
        this.Add(new AppleContainer(this));
    }

    public OrangeContainer Oranges
    {
        get { return (OrangeContainer)this.Items[0]; }
    }

    public AppleContainer Apples
    {
        get { return (AppleContainer)this.Items[1]; }
    }

    public decimal TotalWeight
    {
        get { return _totalWeight; }
        set { _totalWeight = value; }
    }

    internal void UpdateWeight(IFruit caller)
    {
        _totalWeight = 0;
        foreach (Orange orng in (OrangeContainer)this.Items[0])
        {
            _totalWeight += orng.Weight;
        }
        foreach (Apple appl in (AppleContainer)this.Items[1])
        {
            _totalWeight += appl.Weight;
        }
    }

最佳答案

每当添加、删除项目或任何项目的 Weight 属性发生更改时,您都需要调用 FruitBasket 的 INotifyPropertyChanged.PropertyChanged 事件。

让我们将其分为两个任务:

  1. 添加、删除商品或更改商品重量时,应重新计算 TotalWeight。我们需要处理这些事件。
  2. 引发 FruitBasket.PropertyChanged 事件

为了遵循单一职责原则,我将这两个任务分为两个类:

1) - 这处理项目的 PropertyChanged 事件:

public abstract class ExtendedObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
    protected override void ClearItems()
    {
        foreach (var item in Items) item.PropertyChanged -= ItemPropertyChanged;
        base.ClearItems();
    }

    protected override void InsertItem(int index, T item)
    {
        item.PropertyChanged += ItemPropertyChanged;
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        this[index].PropertyChanged -= ItemPropertyChanged;
        base.RemoveItem(index);
    }

    protected override void SetItem(int index, T item)
    {
        this[index].PropertyChanged -= ItemPropertyChanged;
        item.PropertyChanged += ItemPropertyChanged;
        base.SetItem(index, item);
    }

    abstract void ItemPropertyChanged(object sender, PropertyChangedEventArgs e);
}

2) - 必要时重新计算 TotalWeight

public class FruitBasket : ExtendedObservableCollection<IFruit>
{
    protected override void ItemPropertyChanged(object sender, PropertyChangedEventArgs e){
        UpdateWeight();
        OnPropertyChanged("TotalWeight")
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        UpdateWeight();
        OnPropertyChanged("TotalWeight")
        base.OnCollectionChanged(e);
    }
}

当然你的Fruit应该实现INotifyPropertyChanged接口(interface)。您会发现很多如何做到这一点的示例。非常简单。

关于c# - 在 ObservableCollection 上触发 InotifyPropertyChanged/CollectionChanged,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30444874/

相关文章:

c# - 如何为 List<T> 创建属性

wpf - VirtualizingStackPanel 不会清除 ItemTemplate 中 TextBoxes 的文本

c# - 使用 Converter 时未注册 CollectionChanged 事件?

wpf - 操作 ObservableCollection 与替换列表

c# - 在 C# 中将字符串散列为颜色

javascript - 将 JavaScript 函数值转发到 C#

c# - MVVM轻信使,ViewModel之间的通信

java - 观察者模式或其他模式

c# - 复制一个 ObservableCollection 项

c# - HtmlRenderer 不从 css 渲染背景图像