引用其他集合的项目的集合

时间:2012-05-02 20:00:21

标签: c# collections

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

我有一个包含大量自定义类的ObservableCollection - 我们称之为“MainCollection”。我的大部分代码都是在持续的基础上更新MainCollection中这些类的值,一切正常。

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

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

6 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

也许您正在寻找CollectionView class

  

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

然而,

  

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

因此,最好的起点可能是How to: Sort and Group Data Using a View in XAML。可以在CollectionView页面的底部找到这个和其他一些how-to文章。

答案 2 :(得分:0)

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

这样的东西
public List<Whatever> Items
{
    get
    {
        return MainCollection.Where( x => [someCondition] ).ToList();
    }
}

答案 3 :(得分: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 };  

如果你需要观察,那么只需将序列传递给ctor:

var observableColl = new ObservableCollection(newCollection);

答案 4 :(得分:0)

更新MainCollection以添加此分组功能

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

  Update()
  {
        TheLookup.Add(//...
        //do work
  }
}

答案 5 :(得分: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: