我试图弄清楚是否有办法在C#4.0中执行以下操作:
我有一个包含大量自定义类的ObservableCollection - 我们称之为“MainCollection”。我的大部分代码都是在持续的基础上更新MainCollection中这些类的值,一切正常。
我现在需要创建一个'集合'[或者在WPF DataGrid DataContext绑定中使用的东西],它只是将MainCollection中的类分组到底层类中的单个参数上。
有没有办法做到这一点,每当MainCollection中的项目更新时,这个新的'伪集合'也是如此。
答案 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: