namespace Caliburn.Micro { using System.Collections.Specialized; using System.Linq; using System.Windows; using System.Windows.Interactivity; using Caliburn.Micro.Core; /// /// A collection that can exist as part of a behavior. /// /// The type of item in the attached collection. public class AttachedCollection : FreezableCollection, IAttachedObject where T : DependencyObject, IAttachedObject { DependencyObject associatedObject; /// /// Creates an instance of /// public AttachedCollection() { ((INotifyCollectionChanged)this).CollectionChanged += OnCollectionChanged; } /// /// Attached the collection. /// /// The dependency object to attach the collection to. public void Attach(DependencyObject dependencyObject) { WritePreamble(); associatedObject = dependencyObject; WritePostscript(); this.Apply(x => x.Attach(associatedObject)); } /// /// Detaches the collection. /// public void Detach() { this.Apply(x => x.Detach()); WritePreamble(); associatedObject = null; WritePostscript(); } DependencyObject IAttachedObject.AssociatedObject { get { return associatedObject; } } /// /// Called when an item is added from the collection. /// /// The item that was added. protected virtual void OnItemAdded(T item) { if (associatedObject != null) item.Attach(associatedObject); } /// /// Called when an item is removed from the collection. /// /// The item that was removed. protected virtual void OnItemRemoved(T item) { if(item.AssociatedObject != null) item.Detach(); } void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch(e.Action) { case NotifyCollectionChangedAction.Add: e.NewItems.OfType().Where(x => !Contains(x)).Apply(OnItemAdded); break; case NotifyCollectionChangedAction.Remove: e.OldItems.OfType().Apply(OnItemRemoved); break; case NotifyCollectionChangedAction.Replace: e.OldItems.OfType().Apply(OnItemRemoved); e.NewItems.OfType().Where(x => !Contains(x)).Apply(OnItemAdded); break; case NotifyCollectionChangedAction.Reset: this.Apply(OnItemRemoved); this.Apply(OnItemAdded); break; } } } }