ObservableCollectionの範囲を持つ機能

ObservableCollectionクラスは、追加、削除などを許可しません。 要素のコレクション。

このような機能を追加するには、必要な機能を実装するこのクラスの子孫を作成できます。





目的:

コレクションに大幅な変更を加えた複数のPropertyChangedおよびOnCollectionChangedイベントを回避します。構文のゲインは実質的に無視でき、役割を果たしません。



ObservableCollectionには、Collectionから継承されたプロパティがあります。

protected IList<T> Items { get; }
      
      





一緒に仕事をする必要があります。



改訂テンプレートは次のとおりです。

1)変更を確認します。
 protected void CheckReentrancy();
      
      





2)ロジックに従って要素を処理します。
 protected IList<T> Items { get; }
      
      





3)プロパティ「Count」および「Item []」のPropertyChangedイベントを発生させます。

 OnPropertyChanged(new PropertyChangedEventArgs("Count")); OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
      
      





4)イベントパラメータを使用してCollectionChangedイベントを発生させます。タイプResetを変更し、パラメータOldItemsとNewItemsを渡さないでください。

 OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
      
      







短所:

項目4により、CollectionChangedイベントハンドラーのOldItemsとNewItemsは空であるため、これらを操作することはできません。 これは、一部のWPFコントロールが、1つの要素ではなく複数のコレクションの変更で動作しないために必要です。 同時に、変更タイプがResetの場合、これはコレクションが大幅に変更されたことを意味します。これはWPFコントロールでは正常です。 WPFを制御するためのデータソースとして新しいクラスを使用していない場合、ステップ4で、他の種類の変更 、およびOldItemsとNewItemsの入力値を転送し、それらを静かに処理できます。



例:

 using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Linq; namespace Common.Utils { public class ObservableRangeCollection<T> : ObservableCollection<T> { private const string CountString = "Count"; private const string IndexerName = "Item[]"; protected enum ProcessRangeAction { Add, Replace, Remove }; public ObservableRangeCollection() : base() { } public ObservableRangeCollection(IEnumerable<T> collection) : base(collection) { } public ObservableRangeCollection(List<T> list) : base(list) { } protected virtual void ProcessRange(IEnumerable<T> collection, ProcessRangeAction action) { if (collection == null) throw new ArgumentNullException("collection"); var items = collection as IList<T> ?? collection.ToList(); if (!items.Any()) return; this.CheckReentrancy(); if (action == ProcessRangeAction.Replace) this.Items.Clear(); foreach (var item in items) { if (action == ProcessRangeAction.Remove) this.Items.Remove(item); else this.Items.Add(item); } this.OnPropertyChanged(new PropertyChangedEventArgs(CountString)); this.OnPropertyChanged(new PropertyChangedEventArgs(IndexerName)); this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } public void AddRange(IEnumerable<T> collection) { this.ProcessRange(collection, ProcessRangeAction.Add); } public void ReplaceRange(IEnumerable<T> collection) { this.ProcessRange(collection, ProcessRangeAction.Replace); } public void RemoveRange(IEnumerable<T> collection) { this.ProcessRange(collection, ProcessRangeAction.Remove); } } }
      
      







テスト:



 using System; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using Common.Utils; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tests.Common { [TestClass] public class ObservableRangeCollectionTests { [TestMethod] public void AddRangeTest() { var eventCollectionChangedCount = 0; var eventPropertyChangedCount = 0; var orc = new ObservableRangeCollection<int>(new List<int> {0, 1, 2, 3}); orc.CollectionChanged += (sender, e) => { Assert.AreEqual(NotifyCollectionChangedAction.Reset, e.Action); eventCollectionChangedCount++; }; ((INotifyPropertyChanged) orc).PropertyChanged += (sender, e) => { CollectionAssert.Contains(new[] { "Count", "Item[]" }, e.PropertyName); eventPropertyChangedCount++; }; orc.AddRange(new List<int> { 4, 5, 6, 7 }); Assert.AreEqual(8, orc.Count); CollectionAssert.AreEqual(new List<int> { 0, 1, 2, 3, 4, 5, 6, 7 }, orc); Assert.AreEqual(1, eventCollectionChangedCount); Assert.AreEqual(2, eventPropertyChangedCount); } [TestMethod] public void ReplaceRangeTest() { var eventCollectionChangedCount = 0; var eventPropertyChangedCount = 0; var orc = new ObservableRangeCollection<int>(new List<int> { 0, 1, 2, 3 }); orc.CollectionChanged += (sender, e) => { Assert.AreEqual(NotifyCollectionChangedAction.Reset, e.Action); eventCollectionChangedCount++; }; ((INotifyPropertyChanged)orc).PropertyChanged += (sender, e) => { CollectionAssert.Contains(new[] { "Count", "Item[]" }, e.PropertyName); eventPropertyChangedCount++; }; orc.ReplaceRange(new List<int> { 4, 5, 6 }); Assert.AreEqual(3, orc.Count); CollectionAssert.AreEqual(new List<int> { 4, 5, 6 }, orc); Assert.AreEqual(1, eventCollectionChangedCount); Assert.AreEqual(2, eventPropertyChangedCount); } [TestMethod] public void RemoveRangeTest() { var eventCollectionChangedCount = 0; var eventPropertyChangedCount = 0; var orc = new ObservableRangeCollection<int>(new List<int> { 0, 1, 2, 3 }); orc.CollectionChanged += (sender, e) => { Assert.AreEqual(NotifyCollectionChangedAction.Reset, e.Action); eventCollectionChangedCount++; }; ((INotifyPropertyChanged)orc).PropertyChanged += (sender, e) => { CollectionAssert.Contains(new[] { "Count", "Item[]" }, e.PropertyName); eventPropertyChangedCount++; }; orc.RemoveRange(new List<int> { 1, 3, 6 }); Assert.AreEqual(2, orc.Count); CollectionAssert.AreEqual(new List<int> { 0, 2 }, orc); Assert.AreEqual(1, eventCollectionChangedCount); Assert.AreEqual(2, eventPropertyChangedCount); } private enum RangeAction { Add, Replace, Remove } private void EmptyRangeTest(RangeAction action) { var eventCollectionChangedCount = 0; var eventPropertyChangedCount = 0; var orc = new ObservableRangeCollection<int>(new List<int> { 0, 1, 2, 3 }); orc.CollectionChanged += (sender, e) => { eventCollectionChangedCount++; }; ((INotifyPropertyChanged)orc).PropertyChanged += (sender, e) => { eventPropertyChangedCount++; }; switch (action) { case RangeAction.Replace: orc.ReplaceRange(new List<int>()); break; case RangeAction.Remove: orc.RemoveRange(new List<int>()); break; default: orc.AddRange(new List<int>()); break; } Assert.AreEqual(4, orc.Count); CollectionAssert.AreEqual(new List<int> { 0, 1, 2, 3 }, orc); Assert.AreEqual(0, eventCollectionChangedCount); Assert.AreEqual(0, eventPropertyChangedCount); } [TestMethod] public void AddEmptyRangeTest() { this.EmptyRangeTest(RangeAction.Add); } [TestMethod] public void ReplaceEmptyRangeTest() { this.EmptyRangeTest(RangeAction.Replace); } [TestMethod] public void RemoveEmptyRangeTest() { this.EmptyRangeTest(RangeAction.Remove); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void AddNullRangeTest() { new ObservableRangeCollection<int>().AddRange(null); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ReplaceNullRangeTest() { new ObservableRangeCollection<int>().ReplaceRange(null); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void RemoveNullRangeTest() { new ObservableRangeCollection<int>().RemoveRange(null); } } }
      
      






All Articles