如何使用CollectionView功能处理CompositeCollection?

时间:2021-06-20 14:04:52

Is there a way to get notified when CompositeCollection's current location changes?

当CompositeCollection的当前位置发生变化时,有没有办法得到通知?

I need to have the CompositeCollection monitored by a CollectionView, any ideas are welcommed.

我需要通过CollectionView监控CompositeCollection,任何想法都很受欢迎。

3 个解决方案

#1


6  

You can detect when the current item has changed by monitoring the ICollectionView.CurrentChanged event of your CollectionView. The following code works for me:

您可以通过监视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"

When I change the selection in the ListBox, the message box displays.

当我更改ListBox中的选择时,将显示消息框。

Regarding filtering, sorting and grouping, as per Aron's answer these are not available on a view over a CompositeCollection. But for the record here are the ways you can detect changes for views that do support these features:

关于过滤,排序和分组,根据Aron的回答,这些在CompositeCollection的视图上不可用。但是,对于此处的记录,您可以检测支持这些功能的视图的更改:

  • It looks like you'll get a CollectionChanged event when the filter changes, though I can't find this documented.
  • 看起来当过滤器发生变化时你会得到一个CollectionChanged事件,尽管我找不到这个记录。
  • SortDescriptions is SortDescriptionCollection which is INotifyCollectionChanged, so hook up a CollectionChanged event handler on the SortDescriptions property.
  • SortDescriptions是SortDescriptionCollection,它是INotifyCollectionChanged,因此在SortDescriptions属性上挂钩CollectionChanged事件处理程序。
  • GroupDescriptions is ObservableCollection<GroupDescription>, so hook up a CollectionChanged event handler on the GroupDescriptions property.
  • GroupDescriptions是ObservableCollection ,因此在GroupDescriptions属性上挂钩CollectionChanged事件处理程序。

#2


0  

You cant run a CollectionView on a copmposite collection, see here

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

#3


0  

I ran into the same problem: I needed sorting of a CompositeCollection. I wrote the following class that solves the problem, at least for ObservableCollections of the same type.

我遇到了同样的问题:我需要对CompositeCollection进行排序。我编写了以下类来解决问题,至少对于相同类型的ObservableCollections。

The idea is to maintain the composite collection as an ordinary observable collection, and update it as the underlying collections change. Then the resulting collection (AllNodes) can be used in the user interface, and it supports CollectionView just fine.

我们的想法是将复合集合维护为普通的可观察集合,并在底层集合发生更改时对其进行更新。然后生成的集合(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;
        }
    }
}

#1


6  

You can detect when the current item has changed by monitoring the ICollectionView.CurrentChanged event of your CollectionView. The following code works for me:

您可以通过监视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"

When I change the selection in the ListBox, the message box displays.

当我更改ListBox中的选择时,将显示消息框。

Regarding filtering, sorting and grouping, as per Aron's answer these are not available on a view over a CompositeCollection. But for the record here are the ways you can detect changes for views that do support these features:

关于过滤,排序和分组,根据Aron的回答,这些在CompositeCollection的视图上不可用。但是,对于此处的记录,您可以检测支持这些功能的视图的更改:

  • It looks like you'll get a CollectionChanged event when the filter changes, though I can't find this documented.
  • 看起来当过滤器发生变化时你会得到一个CollectionChanged事件,尽管我找不到这个记录。
  • SortDescriptions is SortDescriptionCollection which is INotifyCollectionChanged, so hook up a CollectionChanged event handler on the SortDescriptions property.
  • SortDescriptions是SortDescriptionCollection,它是INotifyCollectionChanged,因此在SortDescriptions属性上挂钩CollectionChanged事件处理程序。
  • GroupDescriptions is ObservableCollection<GroupDescription>, so hook up a CollectionChanged event handler on the GroupDescriptions property.
  • GroupDescriptions是ObservableCollection ,因此在GroupDescriptions属性上挂钩CollectionChanged事件处理程序。

#2


0  

You cant run a CollectionView on a copmposite collection, see here

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

#3


0  

I ran into the same problem: I needed sorting of a CompositeCollection. I wrote the following class that solves the problem, at least for ObservableCollections of the same type.

我遇到了同样的问题:我需要对CompositeCollection进行排序。我编写了以下类来解决问题,至少对于相同类型的ObservableCollections。

The idea is to maintain the composite collection as an ordinary observable collection, and update it as the underlying collections change. Then the resulting collection (AllNodes) can be used in the user interface, and it supports CollectionView just fine.

我们的想法是将复合集合维护为普通的可观察集合,并在底层集合发生更改时对其进行更新。然后生成的集合(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;
        }
    }
}