ObservableCollection 还监视集合中元素的变化 [英] ObservableCollection that also monitors changes on the elements in collection

查看:57
本文介绍了ObservableCollection 还监视集合中元素的变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is there a collection (BCL or other) that has the following characteristics:

如果集合发生更改,则发送事件,如果集合中的任何元素发送 PropertyChanged 事件,则发送事件.类似于 ObservableCollection,其中 T: INotifyPropertyChanged 和集合也在监视元素的变化.

Sends event if collection is changed AND sends event if any of the elements in the collection sends a PropertyChanged event. Sort of an ObservableCollection<T> where T: INotifyPropertyChanged and the collection is also monitoring the elements for changes.

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

I could wrap an observable collection my self and do the event subscribe/unsubscribe when elements in the collection are added/removed but I was just wondering if any existing collections did this already?

推荐答案

自己快速实现:

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 内部触发的新事件进行扩展

Admitted, it would be kind of confusing and misleading to have the PropertyChanged fire on the collection when the property that actually changed is on a contained element, but it would fit my specific purpose. It could be extended with a new event that is fired instead inside ContainerElementChanged

想法?

应注意 BCL ObservableCollection 仅通过显式实现公开 INotifyPropertyChanged 接口,因此您需要提供强制转换才能像这样附加到事件:

Should note that the BCL ObservableCollection only exposes the INotifyPropertyChanged interface through an explicit implementation so you would need to provide a cast in order to attach to the event like so:

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

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

Added handling of ClearItems, thanks Josh

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

Added a correct unsubscribe for PropertyChanged, thanks Mark

哇,这真的是边学边学:).KP 指出,当 a 包含的元素发生更改时,该事件是在集合作为发送方而不是元素的情况下触发的.他建议在标有 new 的类上声明一个 PropertyChanged 事件.这会有一些问题,我将尝试用下面的示例来说明:

Wow, this is really learn-as-you-go :). KP noted that the event was fired with the collection as sender and not with the element when the a contained element changes. He suggested declaring a PropertyChanged event on the class marked with new. This would have a few issues which I'll try to illustrate with the sample below:

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

您可以从示例中看到,覆盖"事件具有副作用,即您在订阅事件时需要非常小心使用哪种类型的变量,因为这决定了您接收哪些事件.

You can see from the sample that 'overriding' the event has the side effect that you need to be extremely careful of which type of variable you use when subscribing to the event since that dictates which events you receive.

这篇关于ObservableCollection 还监视集合中元素的变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆