Gaz*_*yer 28 c# collections performance insert observablecollection
我有一个ObservableCollection项目绑定到我的视图中的列表控件.
我有一种情况需要在集合的开头添加一大块值.
Collection<T>.Insertdocumentation将每个插入指定为O(n)操作,每个插入也生成一个CollectionChanged通知.
因此,我理想地希望在一次移动中插入整个范围的项目,这意味着只有一个基础列表的随机播放,并且希望有一个CollectionChanged通知(可能是"重置").
Collection<T>不公开任何执行此操作的方法.List<T>有InsertRange(),但是IList<T>,这Collection<T>暴露了通过其Items属性不会.
有没有办法做到这一点?
dri*_*iis 52
ObservableCollection公开了一个受保护的Items属性,它是没有通知语义的底层集合.这意味着您可以通过继承ObservableCollection来构建一个可以满足您需求的集合:
class RangeEnabledObservableCollection<T> : ObservableCollection<T>
{
public void InsertRange(IEnumerable<T> items)
{
this.CheckReentrancy();
foreach(var item in items)
this.Items.Add(item);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
void Main()
{
var collection = new RangeEnabledObservableCollection<int>();
collection.CollectionChanged += (s,e) => Console.WriteLine("Collection changed");
collection.InsertRange(Enumerable.Range(0,100));
Console.WriteLine("Collection contains {0} items.", collection.Count);
}
Run Code Online (Sandbox Code Playgroud)
为了使上述答案有用,无需使用反射派生新的基类,这是一个例子:
public static void InsertRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items)
{
var enumerable = items as List<T> ?? items.ToList();
if (collection == null || items == null || !enumerable.Any())
{
return;
}
Type type = collection.GetType();
type.InvokeMember("CheckReentrancy", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null, collection, null);
var itemsProp = type.BaseType.GetProperty("Items", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
var privateItems = itemsProp.GetValue(collection) as IList<T>;
foreach (var item in enumerable)
{
privateItems.Add(item);
}
type.InvokeMember("OnPropertyChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null,
collection, new object[] { new PropertyChangedEventArgs("Count") });
type.InvokeMember("OnPropertyChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null,
collection, new object[] { new PropertyChangedEventArgs("Item[]") });
type.InvokeMember("OnCollectionChanged", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic, null,
collection, new object[]{ new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)});
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23500 次 |
| 最近记录: |