AttachedCollection.cs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. namespace Caliburn.Micro {
  2. using System.Collections.Specialized;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Interactivity;
  6. using Caliburn.Micro.Core;
  7. /// <summary>
  8. /// A collection that can exist as part of a behavior.
  9. /// </summary>
  10. /// <typeparam name="T">The type of item in the attached collection.</typeparam>
  11. public class AttachedCollection<T> : FreezableCollection<T>, IAttachedObject
  12. where T : DependencyObject, IAttachedObject {
  13. DependencyObject associatedObject;
  14. /// <summary>
  15. /// Creates an instance of <see cref="AttachedCollection{T}"/>
  16. /// </summary>
  17. public AttachedCollection() {
  18. ((INotifyCollectionChanged)this).CollectionChanged += OnCollectionChanged;
  19. }
  20. /// <summary>
  21. /// Attached the collection.
  22. /// </summary>
  23. /// <param name="dependencyObject">The dependency object to attach the collection to.</param>
  24. public void Attach(DependencyObject dependencyObject) {
  25. WritePreamble();
  26. associatedObject = dependencyObject;
  27. WritePostscript();
  28. this.Apply(x => x.Attach(associatedObject));
  29. }
  30. /// <summary>
  31. /// Detaches the collection.
  32. /// </summary>
  33. public void Detach() {
  34. this.Apply(x => x.Detach());
  35. WritePreamble();
  36. associatedObject = null;
  37. WritePostscript();
  38. }
  39. DependencyObject IAttachedObject.AssociatedObject {
  40. get { return associatedObject; }
  41. }
  42. /// <summary>
  43. /// Called when an item is added from the collection.
  44. /// </summary>
  45. /// <param name="item">The item that was added.</param>
  46. protected virtual void OnItemAdded(T item) {
  47. if (associatedObject != null)
  48. item.Attach(associatedObject);
  49. }
  50. /// <summary>
  51. /// Called when an item is removed from the collection.
  52. /// </summary>
  53. /// <param name="item">The item that was removed.</param>
  54. protected virtual void OnItemRemoved(T item) {
  55. if(item.AssociatedObject != null)
  56. item.Detach();
  57. }
  58. void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
  59. switch(e.Action) {
  60. case NotifyCollectionChangedAction.Add:
  61. e.NewItems.OfType<T>().Where(x => !Contains(x)).Apply(OnItemAdded);
  62. break;
  63. case NotifyCollectionChangedAction.Remove:
  64. e.OldItems.OfType<T>().Apply(OnItemRemoved);
  65. break;
  66. case NotifyCollectionChangedAction.Replace:
  67. e.OldItems.OfType<T>().Apply(OnItemRemoved);
  68. e.NewItems.OfType<T>().Where(x => !Contains(x)).Apply(OnItemAdded);
  69. break;
  70. case NotifyCollectionChangedAction.Reset:
  71. this.Apply(OnItemRemoved);
  72. this.Apply(OnItemAdded);
  73. break;
  74. }
  75. }
  76. }
  77. }