Chain CollectionChanged Events

时间:2016-11-30 21:35:09

标签: events event-handling system.reactive observablecollection reactive-programming

我试图看看如何将x个ObservableCollections.CollectionChanged事件链接在一起,将N级深度对象树暴露给消费者可以收听的单个父级CollectionChanged事件?基本上我想将所有子CollectionChanged事件汇集或冒泡到最顶层的父级。我已经注意到一些解决方案,解决类似的问题会假设一个固定的级别,比如2个深度。我的想法是支持任何程度的深度。

最初我曾希望我可以将FieldInfos的实例传递给子构造函数并直接附加到处理程序。但是我得到一个错误,指出“事件'CollectionChanged'只能出现在+ =或 - =的左侧。

谢谢,

public class FieldInfos
    {
        public event NotifyCollectionChangedEventHandler CollectionChanged;

        private ObservableCollection<Field> _fields;

        public ObservableCollection<Field> Fields => _fields ?? (_fields = new ObservableCollection<Field>());
    }



    public class Field
    {
        public string Name;

        private ObservableCollection<FieldInstance> _instances;
        public ObservableCollection<FieldInstance> Instances => _instances ?? (_instances = new ObservableCollection<FieldInstance>());
    }

    public class FieldInstance
    {
        public string Id { get; set; }
    }

1 个答案:

答案 0 :(得分:1)

最简单的方法是原始ObservableCollection<T>的子类。

您需要至少一个界面才能避免协方差问题。您还可以拥有自己的类来实现INotifyDescendantsChanged接口。

public interface INotifyDescendantsChanged
{
    event NotifyCollectionChangedEventHandler DescendantsChanged;
}

public class ObservableBubbleCollection<T> : ObservableCollection<T>, INotifyDescendantsChanged
{
    public event NotifyCollectionChangedEventHandler DescendantsChanged;
    protected virtual void OnDescendantsChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler handler = DescendantsChanged;
        if (handler != null)
            handler(sender, e);
    }

    private readonly Func<T, INotifyDescendantsChanged> childSelector;
    public ObservableBubbleCollection() { }
    public ObservableBubbleCollection(Func<T, INotifyDescendantsChanged> childSelector)
    {
        this.childSelector = childSelector;
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnCollectionChanged(e);
        OnDescendantsChanged(this, e);

        if (childSelector == null)
            return;

        if (e.NewItems != null)
            foreach (var item in e.NewItems.Cast<T>())
                childSelector(item).DescendantsChanged += OnDescendantsChanged;

        if (e.OldItems != null)
            foreach (var item in e.OldItems.Cast<T>())
                childSelector(item).DescendantsChanged -= OnDescendantsChanged;
    }
}

要使用它,请替换ObservableCollection的实例并将选择器传递给集合。

public class FieldInfos
{
    private ObservableBubbleCollection<Field> _fields;

    public ObservableBubbleCollection<Field> Fields => _fields ?? (_fields = new ObservableBubbleCollection<Field>(fi => fi.Instances));
}

public class Field
{
    public string Name;

    private ObservableBubbleCollection<FieldInstance> _instances;
    public ObservableBubbleCollection<FieldInstance> Instances => _instances ?? (_instances = new ObservableBubbleCollection<FieldInstance>());
}

public class FieldInstance
{
    public string Id { get; set; }
}

static class Program
{
    static void Main(string[] args)
    {
        var fi = new FieldInfos();
        fi.Fields.DescendantsChanged += (sender, e) =>
        {
            Console.WriteLine("Change from {0}", sender.GetType());
        };

        var field = new Field();
        fi.Fields.Add(field);

        field.Instances.Add(new FieldInstance());
        Console.ReadLine();
    }
}