0

我试图弄清楚是否有办法在 C# 4.0 中执行以下操作:

我有一个包含大量自定义类的 ObservableCollection - 我们称之为“MainCollection”。我的大部分代码都会持续更新 MainCollection 中这些类的值,这一切都很好。

我现在需要创建一个“集合”[或在 WPF DataGrid DataContext 绑定中使用的东西],它只是将 MainCollection 中的类分组到基础类中的单个参数上。

有没有办法做到这一点,每当 MainCollection 中的项目更新时,这个新的“伪集合”也是如此。

4

6 回答 6

1

有一些开源框架可以实现这一点。我使用BindableLinq取得了一些成功。尽管正如主页上所指出的那样,开发已经停滞不前,并且还有其他框架替代方案。

这些库旨在在更新多个级别的依赖项时提供更新(例如集合本身,或集合所依赖的项目的属性,甚至是外部依赖项)。

于 2012-05-02T20:03:10.773 回答
1

也许您正在寻找CollectionView 类

表示用于对数据集合进行分组、排序、过滤和导航的视图。

然而,

您不应在代码中创建此类的对象。要为仅实现 IEnumerable 的集合创建集合视图,请创建一个 CollectionViewSource 对象,将您的集合添加到 Source 属性,然后从 View 属性获取集合视图。

所以也许最好的起点是How to: Sort and Group Data Using a View in XAML。可以在 CollectionView 页面的底部找到这篇文章和其他一些操作指南文章。

于 2012-05-02T20:24:41.057 回答
0

是否可以简单地公开一个按需创建新集合的属性?就像是

public List<Whatever> Items
{
    get
    {
        return MainCollection.Where( x => [someCondition] ).ToList();
    }
}
于 2012-05-02T20:03:07.610 回答
0

换句话说,您想创建 MainCollection 的视图。这听起来像是 LINQ 的工作!

   var newCollection = from item in MainCollection
        group item  by /*item condintion */ into g //use where for filtering
         select new { Prop = g.Prop, Item = g };  

如果您需要 observable,那么只需将序列传递给 ctor:

var observableColl = new ObservableCollection(newCollection);
于 2012-05-02T20:10:05.697 回答
0

更新 MainCollection 以添加此分组功能

class MainCollection 
{
  public Dictionary<TGroupBySingleParameter, TValue> TheLookup{get; private set;}

  Update()
  {
        TheLookup.Add(//...
        //do work
  }
}
于 2012-05-02T20:17:15.250 回答
0

您可以创建一个 FilteredCollection 来侦听更改事件以更新过滤的集合。这允许在源集合发生更改时进行有效的重新过滤。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;

namespace ConsoleApplication26
{
    class FilteredObservableCollection<T> : INotifyCollectionChanged, IEnumerable<T>
    {
        List<T> _FilteredCached;
        ObservableCollection<T> Source;
        Func<T,bool> Filter;

        public FilteredObservableCollection(ObservableCollection<T> source, Func<T,bool> filter)
        {
            Source = source;
            Filter = filter;
            source.CollectionChanged += source_CollectionChanged;
        }

        void source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                var addedMatching = e.NewItems.Cast<T>().Where(Filter).ToList();
                _FilteredCached.AddRange(addedMatching);
                if (addedMatching.Count > 0)
                {
                    CollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, addedMatching));
                }
            }
            else // make life easy and refresh fully
            {
                _FilteredCached = null;
                CollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            if (_FilteredCached == null)
            {
                _FilteredCached = Source.Where(Filter).ToList(); // make it easy to get right. If someone would call e.g. First() only 
                // we would end up with an incomplete filtered collection.
            }

            foreach (var filtered in _FilteredCached)
            {
                yield return filtered;
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public event NotifyCollectionChangedEventHandler CollectionChanged = (o,e) => { };
    }


    class Program
    {
        static void Main(string[] args)
        {
            ObservableCollection<int> data = new ObservableCollection<int>(new int[] { 1, 2, 3, 4, 1 });
            var filteredObservable = new FilteredObservableCollection<int>(data, x => x > 2);
            Print(filteredObservable); // show that filter works
            data.Add(1);
            Print(filteredObservable); // no change
            data.Add(10);
            Print(filteredObservable); // change
            data.Clear();
            Print(filteredObservable); // collection is empy
            data.Add(5);
            Print(filteredObservable); // add item in filter range
            data[0] = 1;
            Print(filteredObservable); // replace it
        }

        static void Print<T>(FilteredObservableCollection<T> coll)
        {
            Console.WriteLine("Filtered: {0}", String.Join(",", coll));
        }
    }

}

这将打印

Filtered: 3,4
Filtered: 3,4
Filtered: 3,4,10
Filtered:
Filtered: 5
Filtered:
于 2012-05-02T21:22:55.600 回答