有效地向ObservableCollection添加一系列值
我有一个ObservableCollection
项目绑定到我的视图中的列表控件。
我有一种情况,我需要在集合的开头添加一大块值。 Collection.Insert
文档将每个插入指定为O(n)操作,每个插入也生成一个CollectionChanged
通知。
因此,我希望在一次移动中插入整个范围的项目,这意味着只有一个基础列表的随机播放,并且希望有一个CollectionChanged
通知(可能是“重置”)。
Collection
不会公开任何执行此操作的方法。 List
具有InsertRange()
,但是IList
, Collection
通过其Items
属性公开不会。
有没有办法做到这一点?
ObservableCollection公开受保护的Items
属性,该属性是没有通知语义的基础集合。 这意味着您可以通过inheritanceObservableCollection来构建一个能够满足您需求的集合:
class RangeEnabledObservableCollection : ObservableCollection { public void InsertRange(IEnumerable items) { this.CheckReentrancy(); foreach(var item in items) this.Items.Add(item); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } }
用法:
void Main() { var collection = new RangeEnabledObservableCollection(); collection.CollectionChanged += (s,e) => Console.WriteLine("Collection changed"); collection.InsertRange(Enumerable.Range(0,100)); Console.WriteLine("Collection contains {0} items.", collection.Count); }
为了使上述答案有用,无需使用reflection派生新的基类,这是一个例子:
public static void InsertRange(this ObservableCollection collection, IEnumerable items) { var enumerable = items as List ?? 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 ; 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)}); }
这个答案没有向我展示DataGrid中的新条目。 这个OnCollectionChanged对我有用:
public class SilentObservableCollection : ObservableCollection { public void AddRange(IEnumerable enumerable) { CheckReentrancy(); int startIndex = Count; foreach (var item in enumerable) Items.Add(item); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List (enumerable), startIndex)); OnPropertyChanged(new PropertyChangedEventArgs("Count")); OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); } }
示例:所需步骤0,10,20,30,40,50,60,70,80,90,100 – > min = 0,max = 100,steps = 11
static int min = 0; static int max = 100; static int steps = 11; private ObservableCollection restartDelayTimeList = new ObservableCollection ( Enumerable.Range(0, steps).Select(l1 => (min + (max - min) * ((double)l1 / (steps - 1))).ToString()) );