Wpf 如何使用CollectionView功能处理CompositeCollection?

Wpf 如何使用CollectionView功能处理CompositeCollection?,wpf,observablecollection,collectionviewsource,compositecollection,Wpf,Observablecollection,Collectionviewsource,Compositecollection,当CompositeCollection的当前位置发生更改时,是否有方法获得通知 我需要让CollectionView监视CompositeCollection,任何想法都会受到欢迎。您可以通过监视CollectionView的ICollectionView.CurrentChanged事件来检测当前项目何时发生了更改。以下代码适用于我: CompositeCollection cc = new CompositeCollection(); cc.Add(new CollectionContai

当CompositeCollection的当前位置发生更改时,是否有方法获得通知


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

您可以通过监视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"
当我更改列表框中的选择时,将显示消息框

关于过滤、排序和分组,根据Aron的回答,这些在CompositeCollection的视图中不可用。但请注意,以下是检测支持这些功能的视图的更改的方法:

  • 当过滤器更改时,看起来您将获得CollectionChanged事件,尽管我找不到此文档
  • SortDescriptions是SortDescriptionCollection,它是INotifyCollectionChanged,因此在SortDescriptions属性上连接CollectionChanged事件处理程序
  • GroupDescriptions是
    ObservableCollection
    ,因此在GroupDescriptions属性上连接CollectionChanged事件处理程序

您无法在复合网站集合上运行CollectionView,请参见

我遇到了相同的问题:我需要对复合集合进行排序。我编写了下面的类来解决这个问题,至少对于相同类型的可观测集合是这样

其思想是将复合集合维护为一个普通的可观察集合,并随着基础集合的更改进行更新。然后,生成的集合(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;
        }
    }
}
使用System.Collections.ObjectModel;
使用System.Collections.Specialized;
使用System.Linq;
命名空间Util{
公共类ObservableCollectionCollector{
私有类ReplacableObservableCollection:ObservableCollection{
公共无效替换(int idx,T v){
设置项(idx,v);
}
}
私有只读ReplacableObservableCollection所有节点;
私有只读可观察集合[]colls;
私有只读int[]镜头;
公共ObservableCollectionCollector(参数ObservableCollection[]colls){
this.colls=colls;
allNodes=新的ReplacableObservableCollection();
foreach(colls中的变量l){
foreach(l中的变量e)
添加(e);
l、 CollectionChanged+=HandleCollectionChanged;
}
lens=colls.Select(c=>c.Count.ToArray();
}
public ReadOnlyObservableCollection所有节点{
获取{返回新的ReadOnlyObservableCollection(allNodes);}
}
私有无效HandleCollectionChanged(对象发送方,NotifyCollectionChangedEventArgs e){
int i0=0;
int-ci=0;
foreach(colls中的变量l){
if(l==发送方)
打破
i0+=l.计数;
++词;
}
开关(电动){
案例NotifyCollectionChangedAction。添加:
对于(int i=0;i
问题在于我使用的CompositeCollection绑定到两个不同的CollectionViewSource对象。当我更改列表框中的位置(IsSynchronizedWithCurrentItem显然设置为True)时,CurrentChangeing(ed)不会被触发。那么您在同一个集合上有两个CVSE?这是个愚蠢的问题,但是你确定你订阅了正确的CVS.View上的事件吗?建议您更新问题以显示不起作用的代码。也许您可以告诉我怎么做。应监控所需的is电流变化。从我所有的尝试中得出的结论是,事件没有被触发。这不是一个愚蠢的奎斯汀,我认为它比它更复杂;我希望不是。对不起,我的意思是我的问题(“你确定你在正确的CVS视图上订阅了活动吗?”)是一个愚蠢的“理智检查”问题。我不认为你最初的问题是愚蠢的,也不是有意提出这个问题的。哦,谢谢。无论如何,我认为我订阅了正确的CVS,我甚至创建了一个测试CVS,它的源是CompositeCollection,我没有得到通知,你有没有遇到过这种情况?任何例子都将不胜感激。谢谢你的努力!顺便说一句,我查看了你的博客,这里有很多令人惊奇的东西!排序和筛选对我来说不那么重要。首要任务是改变现状。顺便说一句,看看我和伊托尔森的讨论,他说他很快就要发布代码了。让我们祈祷上帝……你可以,因为这就是货币的运作方式——虽然没有意识到局限性——谢谢!