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;
}
}
}
}