如何处理带有CollectionView功能的CompositeCollection?

7

当CompositeCollection的当前位置发生变化时,有没有一种获取通知的方式?

我需要让CollectionView监视CompositeCollection,欢迎任何想法。

3个回答

7
您可以通过监视CollectionView的ICollectionView.CurrentChanged事件来检测当前项何时发生更改。以下代码适用于我:

您可以通过监视CollectionView的ICollectionView.CurrentChanged事件来检测当前项何时发生更改。以下代码适用于我:

CompositeCollection cc = new CompositeCollection();
cc.Add(new CollectionContainer { Collection = new string[] { "Oh No!", "Fie" } });
cc.Add(new CollectionContainer { Collection = new string[] { "Zounds", "Ods Bodikins" } });
CollectionViewSource cvs = new CollectionViewSource { Source = cc };

// Subscribing to CurrentChanged on the ICollectionView
cvs.View.CurrentChanged += (o, e) => MessageBox.Show("current changed");

lb.ItemsSource = cvs.View;  // lb is a ListBox with IsSynchronizedWithCurrentItem="True"

当我在ListBox中更改选择时,消息框会显示。
关于过滤、排序和分组,根据Aron的回答,这些功能在CompositeCollection上的视图中不可用。但是为了记录,以下是您可以检测支持这些功能的视图的更改方式:
- 当过滤器更改时,似乎会收到CollectionChanged事件,尽管我找不到文档证明。 - SortDescriptions是SortDescriptionCollection,它是INotifyCollectionChanged,因此在SortDescriptions属性上挂接CollectionChanged事件处理程序。 - GroupDescriptions是ObservableCollection,因此在GroupDescriptions属性上挂接CollectionChanged事件处理程序。

所以你有两个针对同一集合的 CVSes?问题有点傻,但你确定你正在订阅正确的 CVS.View 上的事件吗?建议你更新问题以显示不起作用的代码。 - itowlson
也许你可以告诉我如何做。期望监视CurrentChanging事件。从我的所有尝试中得出的结论是,该事件未被触发。这不是一个愚蠢的问题,我认为它比看起来更复杂;但愿不是这样。 - Shimmy Weitzhandler
抱歉,我的问题(“你确定你正在正确的CVS视图上订阅事件吗?”)只是一个愚蠢的“健全性检查”问题。我并不认为您最初的问题是愚蠢的,并且也没有意味着如此。 - itowlson
哦,没关系,谢谢。 不管怎样,我认为我已经订阅了正确的CVS,我甚至创建了一个测试CVS,它的源是CompositeCollection,但我没有收到通知,你有遇到过这种情况吗?有例子就更好了。 感谢您的所有努力! 顺便说一句,我看了你的博客,里面有很棒的东西! - Shimmy Weitzhandler
有没有一种方法可以对CompositeCollection进行排序和过滤? 有什么解决办法或替代方案吗? - Shimmy Weitzhandler
显示剩余3条评论

0
我遇到了同样的问题:我需要对CompositeCollection进行排序。我编写了以下类来解决这个问题,至少适用于相同类型的ObservableCollections。
思路是将复合集合维护为普通的可观察集合,并在基础集合更改时更新它。然后可以在用户界面中使用生成的集合(AllNodes),并且它支持CollectionView。
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;

namespace Util {
    public class ObservableCollectionCollector<T> {
        private class ReplacableObservableCollection : ObservableCollection<T> {
            public void Replace(int idx, T v) {
                SetItem(idx, v);
            }
        }
        private readonly ReplacableObservableCollection allNodes;
        private readonly ObservableCollection<T>[] colls;
        private readonly int[] lens;

        public ObservableCollectionCollector(params ObservableCollection<T>[] colls) {
            this.colls = colls;
            allNodes = new ReplacableObservableCollection();
            foreach (var l in colls) {
                foreach (var e in l)
                    allNodes.Add(e);
                l.CollectionChanged += HandleCollectionChanged;
            }
            lens = colls.Select(c => c.Count).ToArray();
        }

        public ReadOnlyObservableCollection<T> AllNodes {
            get { return new ReadOnlyObservableCollection<T>(allNodes); }
        }

        private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
            int i0 = 0;
            int ci = 0;
            foreach (var l in colls) {
                if (l == sender)
                    break;
                i0 += l.Count;
                ++ci;
            }
            switch (e.Action) {
                case NotifyCollectionChangedAction.Add:
                    for (int i = 0; i < e.NewItems.Count; ++i)
                        allNodes.Insert(i0 + e.NewStartingIndex + i, (T)e.NewItems[i]);
                    break;
                case NotifyCollectionChangedAction.Move:
                    for (int i = 0; i < e.OldItems.Count; ++i)
                        allNodes.Move(i0 + e.OldStartingIndex + i, i0 + e.NewStartingIndex + i);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    for (int i = 0; i < e.OldItems.Count; ++i)
                        allNodes.RemoveAt(i0 + e.OldStartingIndex);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    for (int i = 0; i < e.NewItems.Count; ++i)
                        allNodes.Replace(i0 + e.OldStartingIndex + i, (T)e.NewItems[i]);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    for (int i = 0; i < lens[ci]; ++i)
                        allNodes.RemoveAt(i0);
                    break;
            }
            lens[ci] = ((ObservableCollection<T>)sender).Count;
        }
    }
}

0

你不能在复合集合上运行CollectionView,请查看这里


排序和过滤对我来说不是很重要。最重要的是CurrentChanging。 顺便说一下,看看我与itowlson的讨论,他说他很快就会发布代码。希望有好东西... - Shimmy Weitzhandler
你可以这样做,因为这就是货币的工作方式——虽然之前没有意识到这些限制——谢谢! - itowlson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接