c# - ObservableCollection 也监视集合中元素的变化

标签 c# collections

是否有一个集合(BCL或其他)具有以下特征:

如果集合发生变化则发送事件并且如果集合中的任何元素发送一个 PropertyChanged 则发送事件事件。有点像 ObservableCollection<T>其中 T: INotifyPropertyChanged并且该集合还监视元素的变化。

我可以自己包装一个可观察集合,并在添加/删除集合中的元素时执行事件订阅/取消订阅,但我只是想知道是否有任何现有集合已经这样做了?

最佳答案

我自己做了一个快速实现:

public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        Unsubscribe(e.OldItems);
        Subscribe(e.NewItems);
        base.OnCollectionChanged(e);
    }

    protected override void ClearItems()
    {
        foreach(T element in this)
            element.PropertyChanged -= ContainedElementChanged;

        base.ClearItems();
    }

    private void Subscribe(IList iList)
    {
        if (iList != null)
        {
            foreach (T element in iList)
                element.PropertyChanged += ContainedElementChanged;
        }
    }

    private void Unsubscribe(IList iList)
    {
        if (iList != null)
        {
            foreach (T element in iList)
                element.PropertyChanged -= ContainedElementChanged;
        }
    }

    private void ContainedElementChanged(object sender, PropertyChangedEventArgs e)
    {
        OnPropertyChanged(e);
    }
}

承认,当实际更改的属性位于包含的元素上时,让 PropertyChanged 在集合上触发会有点困惑和误导,但这符合我的特定目的。可以使用在 ContainerElementChanged 内部触发的新事件来扩展它

想法?

编辑:应注意,BCL ObservableCollection 仅通过显式实现公开 INotifyPropertyChanged 接口(interface),因此您需要提供强制转换才能附加到事件,如下所示:

ObservableCollectionEx<Element> collection = new ObservableCollectionEx<Element>();
((INotifyPropertyChanged)collection).PropertyChanged += (x,y) => ReactToChange();

EDIT2:添加了对 ClearItems 的处理,感谢 Josh

EDIT3:为 PropertyChanged 添加了正确的取消订阅,感谢 Mark

EDIT4:哇,这真是边学边学:)。 KP 指出事件是在集合作为发送者时触发的,而不是在包含的元素发生变化时用元素触发的。他建议在标有new 的类上声明 PropertyChanged 事件。这会有一些问题,我将尝试用下面的示例来说明:

  // work on original instance
  ObservableCollection<TestObject> col = new ObservableCollectionEx<TestObject>();
  ((INotifyPropertyChanged)col).PropertyChanged += (s, e) => { Trace.WriteLine("Changed " + e.PropertyName); };

  var test = new TestObject();
  col.Add(test); // no event raised
  test.Info = "NewValue"; //Info property changed raised

  // working on explicit instance
  ObservableCollectionEx<TestObject> col = new ObservableCollectionEx<TestObject>();
  col.PropertyChanged += (s, e) => { Trace.WriteLine("Changed " + e.PropertyName); };

  var test = new TestObject();
  col.Add(test); // Count and Item [] property changed raised
  test.Info = "NewValue"; //no event raised

您可以从示例中看到,“覆盖”事件会产生副作用,您需要在订阅事件时格外小心使用哪种类型的变量,因为它决定了您接收的事件。

关于c# - ObservableCollection 也监视集合中元素的变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/269073/

相关文章:

Java 集合 - 重写 equals 和 hashCode

java - 快速失败迭代器

java - Hibernate中使用List时放置List Index

java - 获取深度对象中的每个对象

c# - 将 System::String^(C# 字符串)转换为 C++ std::string

c# - C# 中事件的无操作订阅者 - 空检查冗余

c# - 将对象添加到 LINQ 中的字典值?

c# - ASP.NET MVC4 Web API MediaTypeFormatter Converter 将 XElement 转换为 JSON

c# - 在 C# 中,如何截断字节 [] 数组

F# 中的 Python 风格集合