Adding a range of values to an ObservableCollection efficiently

前端 未结 4 1280
Happy的楠姐
Happy的楠姐 2020-12-24 06:29

I have an ObservableCollection of items that is bound to a list control in my view.

I have a situation where I need to add a chunk of values to the star

相关标签:
4条回答
  • 2020-12-24 06:55

    To make the above answer useful w/o deriving a new base class using reflection, here's an example:

    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)});
    }
    
    0 讨论(0)
  • 2020-12-24 07:07

    This answer didn't show me the new entries in a DataGrid. This OnCollectionChanged works for me:

    public class SilentObservableCollection<T> : ObservableCollection<T>
    {
        public void AddRange(IEnumerable<T> enumerable)
        {
            CheckReentrancy();
    
            int startIndex = Count;
    
            foreach (var item in enumerable)
                Items.Add(item);
    
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<T>(enumerable), startIndex));
            OnPropertyChanged(new PropertyChangedEventArgs("Count"));
            OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
        }
    }
    
    0 讨论(0)
  • 2020-12-24 07:07

    Example: Desired steps 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<string> restartDelayTimeList = new ObservableCollection<string> (
            Enumerable.Range(0, steps).Select(l1 => (min + (max - min) * ((double)l1 / (steps - 1))).ToString())
        );
    
    0 讨论(0)
  • 2020-12-24 07:13

    The ObservableCollection exposes an protected Items property which is the underlying collection without the notification semantics. This means you can build a collection that does what you want by inheriting 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));
        }
    }
    

    Usage:

    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);  
    }
    
    0 讨论(0)
提交回复
热议问题