0

我有这样的课:

Class A
{
    public ObservableCollection<T> collectionA;
    public ObservableCollection<T> collectionB;
    public T objectA;
}

我想公开另一个属性:

public ObservableCollection<T> All;

包含所有 collectionA、collectionB 和 objectA。

最初,我看到其他问题将我指向 CompositeCollection 类。但是,如果我这样做,似乎每当我更改 collectionA 时,对它的更改不会导致事件通过 CompositeCollection 传播并通知它绑定到的东西(其中一些东西实际上是我自己的类)。

所以,我的第二种方法是一个快速而肮脏的功能:

    public void HookCollection(ObservableCollection<T> dest, ObservableCollection<T> source)
        source.CollectionChanged += new NotifyCollectionChangedEventHandler(delegate(object sender, NotifyCollectionChangedEventArgs e)
            {
                // Apply the same changes to the destination collection
                if (e.Action == NotifyCollectionChangedAction.Reset)
                {
                    foreach (T o in source)
                    {
                        dest.Remove(o);
                    }   
                }
                if (e.NewItems != null)
                {
                    foreach (T o in e.NewItems)
                    {
                        dest.Add(o);
                    }
                }
                if (e.OldItems != null)
                {
                    foreach (T o in e.OldItems)
                    {
                        dest.Remove(o);
                    }
                }  
            });
    }

但我很快发现,在“重置”动作中,原本在源集合中的项目已经被销毁,所以我不知道从目标集合中删除什么。

此属性绑定到具有某些属性的控件,这些属性取决于此列表的内容,即... 整个集合的最小值和最大值。这些又与控件绑定。因此,能够将其作为 IEnumerable 进行迭代将非常有用(而 CompositeCollection 使这变得困难)。

因此,我需要有一种干净的方式来通知列表(和子列表)的更改。

目前,我能看到的唯一解决方案是在我的控件类中,检测 CompositeCollection,然后遍历每个 CollectionContainer 并附加到它的 CollectionChanging 事件(如果有的话)。但是,正如您可以想象的那样,这是一种非常讨厌的方式来挂钩事件。有一些方法可以干净地聚合这些事件会很好。(我以为那是 CompositeCollection 但显然不是?)。

感谢您的任何想法!

4

1 回答 1

0

根据 MSDN NotifyCollectionChangedAction.Reset 意味着

收藏的内容发生了巨大的变化。

在这种情况下, event 参数不会包含旧项目,因为重新扫描整个集合而不处理每个 Add Remove 事件可能会更有效。

为了修复您当前的解决方案,您所要做的就是添加一个函数,该函数重新扫描您的集合并在您收到 NotifyCollectionChangedAction.Reset 操作时运行它。

private void init()
    {
        // if you want it to be thread safe dont forget to lock
        all.Clear();

        foreach (var item in this.collectionA)
        {
            all.Add(item);
        }
        foreach (var item in this.collectionB)
        {
            all.Add(item);
        }
    }

//你的钩子方法应该是这样的:

public void HookCollection(ObservableCollection<int> dest, ObservableCollection<int> source)
   {
    source.CollectionChanged += new NotifyCollectionChangedEventHandler(delegate(object sender, NotifyCollectionChangedEventArgs e)
        {
            // Apply the same changes to the destination collection
            if (e.Action == NotifyCollectionChangedAction.Reset)
            {                   
                this.init();
            }
            if (e.NewItems != null)
            {
                foreach (int o in e.NewItems)
                {
                    dest.Add(o);
                }
            }
            if (e.OldItems != null)
            {
                foreach (int o in e.OldItems)
                {
                    dest.Remove(o);
                }
            }  
        });        

    }
于 2013-06-30T12:38:00.700 回答