如何让嵌套的集合更改事件冒泡

时间:2014-02-11 22:48:00

标签: c# wpf

我有一系列嵌套集合,我需要检测从最上层到最下层的任何位置的更改。首先,我将展示我的代码:

public class CategoricalDataItem
{
    public string XValue { get; set; }

    public double YValue { get; set; }

    public SolidColorBrush Color { get; set; }

    public CategoricalDataItemCollection SimpleSubData { get; set; }
}

[Serializable]
public class CategoricalDataItemCollection : ObservableCollection<CategoricalDataItem>
{
    public string Descriptor { get; set; }
}

此代码的结构用于下钻图表。基本上,我允许5层深。开发人员可以创建CategoricalDataItemCollection的实例,并且对于该集合中的每个CategoricalDataItem,可以创建CategoricalDataItemCollection的新实例,依此类推。我需要知道是否在任何这些嵌套集合中添加或删除了任何项目。 CollectionChanged事件仅检测第一层中的更改。建议将不胜感激。

1 个答案:

答案 0 :(得分:1)

诀窍是监控集合的变化。以下是这样做的示例。

我添加了一个小型测试类,它会在添加新项目时吐出消息。

需要注意的一点是,您实际上正在使用自己继承的CollectionChanged事件,这样您就可以监控进出的孩子并在收集更改时进行监听。请特别注意,这只是一个示例,需要对MyCollectionChanged(...)进行一些抛光和测试,因为还需要处理其他NotifyCollectionChangedAction

[Serializable]
public class CategoricalDataItemCollection : ObservableCollection<CategoricalDataItem>
{
    public string Descriptor { get; set; }

    public CategoricalDataItemCollection()
    {
        this.CollectionChanged += MyCollectionChanged;
    }

    void MyCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
    {
        // There are other actions to handle. This is purely an example.
        if (args.OldItems != null)
        {
            foreach (var oldItem in args.OldItems.Cast<CategoricalDataItem>())
            {
                if (args.Action == NotifyCollectionChangedAction.Remove)
                    oldItem.SimpleSubData.CollectionChanged -= InvokeCollectionChanged;
            }
        }

        if (args.NewItems != null)
        {
            foreach (var newItem in args.NewItems.Cast<CategoricalDataItem>())
            {
                if (args.Action == NotifyCollectionChangedAction.Add)
                    newItem.SimpleSubData.CollectionChanged += InvokeCollectionChanged;
            }
        }
    }

    void InvokeCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
    {
        // This is the tricky part. Nothing actually changed in our collection, but we
        // have to signify that something did.
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

public class TestClass
{
    public void TestNotify()
    {
        var parent = new CategoricalDataItemCollection();
        parent.CollectionChanged += (sender, args) => Debug.Print("Parent Collection Changed");

        var child = new CategoricalDataItem {SimpleSubData = new CategoricalDataItemCollection()};
        child.SimpleSubData.CollectionChanged += (sender, args) => Debug.Print("Child Collection Changed");

        var grandChild = new CategoricalDataItem { SimpleSubData = new CategoricalDataItemCollection()};
        grandChild.SimpleSubData.CollectionChanged += (sender, args) => Debug.Print("Grand Child Collection Changed");

        //Should only output "Parent"
        parent.Add(child);

        //Should only output "Child" and then "Parent"
        child.SimpleSubData.Add(grandChild);

        //Should now output "Grand Child" and then "Child" and then "Parent" messages.
        grandChild.SimpleSubData.Add(new CategoricalDataItem(){SimpleSubData = new CategoricalDataItemCollection()});
    }
}