123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- using System;
- using System.Collections.ObjectModel;
- using System.Collections.Specialized;
- using System.ComponentModel;
- using System.Globalization;
- using System.Windows;
- namespace HandyControl.Interactivity;
- public abstract class AttachableCollection<T> : FreezableCollection<T>, IAttachedObject
- where T : DependencyObject, IAttachedObject
- {
- private DependencyObject _associatedObject;
- private Collection<T> _snapshot;
- internal AttachableCollection()
- {
- INotifyCollectionChanged changed = this;
- changed.CollectionChanged += OnCollectionChanged;
- _snapshot = new Collection<T>();
- }
- public DependencyObject AssociatedObject
- {
- get
- {
- ReadPreamble();
- return _associatedObject;
- }
- }
- DependencyObject IAttachedObject.AssociatedObject => AssociatedObject;
- public void Attach(DependencyObject dependencyObject)
- {
- if (Equals(dependencyObject, AssociatedObject))
- return;
- if (AssociatedObject != null)
- throw new InvalidOperationException();
- if (Interaction.ShouldRunInDesignMode || !(bool) GetValue(DesignerProperties.IsInDesignModeProperty))
- {
- WritePreamble();
- _associatedObject = dependencyObject;
- WritePostscript();
- }
- OnAttached();
- }
- public void Detach()
- {
- OnDetaching();
- WritePreamble();
- _associatedObject = null;
- WritePostscript();
- }
- protected abstract void OnAttached();
- protected abstract void OnDetaching();
- internal abstract void ItemAdded(T item);
- internal abstract void ItemRemoved(T item);
- private void VerifyAdd(T item)
- {
- if (item == null) throw new ArgumentNullException(nameof(item));
- if (_snapshot.Contains(item))
- throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
- ExceptionStringTable.DuplicateItemInCollectionExceptionMessage, new object[]
- {
- typeof(T).Name,
- GetType().Name
- }));
- }
- private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
- {
- switch (e.Action)
- {
- case NotifyCollectionChangedAction.Add:
- var enumerator1 = e.NewItems.GetEnumerator();
- try
- {
- while (enumerator1.MoveNext())
- {
- var current = (T) enumerator1.Current;
- try
- {
- VerifyAdd(current);
- ItemAdded(current);
- }
- finally
- {
- _snapshot.Insert(IndexOf(current), current);
- }
- }
- break;
- }
- finally
- {
- if (enumerator1 is IDisposable disposable)
- disposable.Dispose();
- }
- case NotifyCollectionChangedAction.Remove:
- var enumerator2 = e.OldItems.GetEnumerator();
- try
- {
- while (enumerator2.MoveNext())
- {
- var current = (T) enumerator2.Current;
- ItemRemoved(current);
- _snapshot.Remove(current);
- }
- break;
- }
- finally
- {
- if (enumerator2 is IDisposable disposable)
- disposable.Dispose();
- }
- case NotifyCollectionChangedAction.Replace:
- foreach (T oldItem in e.OldItems)
- {
- ItemRemoved(oldItem);
- _snapshot.Remove(oldItem);
- }
- var enumerator3 = e.NewItems.GetEnumerator();
- try
- {
- while (enumerator3.MoveNext())
- {
- var current = (T) enumerator3.Current;
- try
- {
- VerifyAdd(current);
- ItemAdded(current);
- }
- finally
- {
- _snapshot.Insert(IndexOf(current), current);
- }
- }
- break;
- }
- finally
- {
- if (enumerator3 is IDisposable disposable)
- disposable.Dispose();
- }
- case NotifyCollectionChangedAction.Reset:
- foreach (var obj in _snapshot)
- ItemRemoved(obj);
- _snapshot = new Collection<T>();
- using (var enumerator4 = GetEnumerator())
- {
- while (enumerator4.MoveNext())
- {
- var current = enumerator4.Current;
- VerifyAdd(current);
- ItemAdded(current);
- }
- break;
- }
- }
- }
- }
|