Определим следующее событие (с аргументами):
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В следующей (последней) статье я рассмотрю проблему еще раз и решение.
Комментариев нет:
Отправить комментарий