Определим следующее событие (с аргументами):
public delegate void CollectionChanged(object sender, CollectionChangedEventArgs args); public class CollectionChangedEventArgs:EventArgs { public CollectionChangedEventArgs(ActionType action, int itemIndex) { Action = action; Index = itemIndex; } public ActionType Action { get; private set; } public int Index { get; private set; } } public enum ActionType { Clear, Insert, Remove, Set }
Назначение свойств очевидно. Структура намеренно упрощена и не подразумевает одновременного изменения нескольких членов коллекции (не считая очистки всех).
Определим также следующий обобщенный класс коллекций, которые уведомляют о своих изменениях:
public interface IObservableCollection { event CollectionChanged Changed; } public interface IObservableList<T>:IList<T>, IObservableCollection {} public class ObservableCollection<T> : Collection<T>, IObservableList<T> { public event CollectionChanged Changed; public ObservableCollection() {} public ObservableCollection(IList<T> list):base(list) {} protected void OnChanged(CollectionChangedEventArgs args) { var handler = Changed; if (handler != null) handler(this, args); } #region change notification protected override void ClearItems() { base.ClearItems(); OnChanged(new CollectionChangedEventArgs(ActionType.Clear, -1)); } protected override void InsertItem(int index, T item) { base.InsertItem(index, item); OnChanged(new CollectionChangedEventArgs(ActionType.Insert, index)); } protected override void SetItem(int index, T item) { base.SetItem(index, item); OnChanged(new CollectionChangedEventArgs(ActionType.Set, index)); } protected override void RemoveItem(int index) { base.RemoveItem(index); OnChanged(new CollectionChangedEventArgs(ActionType.Remove, index)); } #endregion }
Соответственно изменим определение объектной модели в классах Page.cs и Block.cs:
// Page.cs private IObservableList_items = new ObservableCollection (); public IObservableList Items... // Block.cs private IObservableList _items = new ObservableCollection (); public IObservableList Items...
Еще одно упрощение состоит в отсутствии проверки на null для коллекций _items. Я стараюсь избегать использования null, если есть возможность использовать пустой массив или шаблон Null object.
Как мы убедимся что решение работает
Мы напишем много тестов следующего вида:[TestFixture] public class ObserverTests { [Test] public void WatchTextItems() { var testee = new Page { Size = new Size(10, 10) }; var observer = new Mock<IRelocateObserver>(); testee.Items.Add(new Block()); testee.Items[0].Items.Add(new TextItem { Rect = new Rectangle(1, 2, 3, 4) }); Observe(testee, observer.Object.Invalidate); // act testee.Items[0].Items[0].Rect = new Rectangle(3, 4, 5, 6); // verify observer.Verify(o => o.Invalidate(new Rectangle(1, 2, 3, 4))); observer.Verify(o => o.Invalidate(new Rectangle(3, 4, 5, 6))); } }Здесь Observe - функция которую мы собираемся тестировать. Вторым аргументом функции является Action
В следующей (последней) статье я рассмотрю проблему еще раз и решение.
Комментариев нет:
Отправить комментарий