PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/V4/MVVM RI/MVVM.Client/Infrastructure/Behaviors/SynchronizeSelectedItems.cs

#
C# | 160 lines | 121 code | 17 blank | 22 comment | 13 complexity | effd91d1d4b634ba5cbb6c4b02edf672 MD5 | raw file
  1. //===================================================================================
  2. // Microsoft patterns & practices
  3. // Composite Application Guidance for Windows Presentation Foundation and Silverlight
  4. //===================================================================================
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8. // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9. // FITNESS FOR A PARTICULAR PURPOSE.
  10. //===================================================================================
  11. // The example companies, organizations, products, domain names,
  12. // e-mail addresses, logos, people, places, and events depicted
  13. // herein are fictitious. No association with any real company,
  14. // organization, product, domain name, email address, logo, person,
  15. // places, or events is intended or should be inferred.
  16. //===================================================================================
  17. using System;
  18. using System.Collections;
  19. using System.Collections.Specialized;
  20. using System.Diagnostics.CodeAnalysis;
  21. using System.Windows;
  22. using System.Windows.Controls;
  23. using System.Windows.Interactivity;
  24. namespace MVVM.Client.Infrastructure.Behaviors
  25. {
  26. /// <summary>
  27. /// Custom behavior that synchronizes the list in <see cref="ListBox.SelectedItems"/> with a collection.
  28. /// </summary>
  29. /// <remarks>
  30. /// This behavior uses a weak event handler to listen for changes on the synchronized collection.
  31. /// </remarks>
  32. public class SynchronizeSelectedItems : Behavior<ListBox>
  33. {
  34. public static readonly DependencyProperty SelectionsProperty =
  35. DependencyProperty.Register(
  36. "Selections",
  37. typeof(IList),
  38. typeof(SynchronizeSelectedItems),
  39. new PropertyMetadata(null, OnSelectionsPropertyChanged));
  40. private bool updating;
  41. private WeakEventHandler<SynchronizeSelectedItems, object, NotifyCollectionChangedEventArgs> currentWeakHandler;
  42. [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
  43. Justification = "Dependency property")]
  44. public IList Selections
  45. {
  46. get { return (IList)this.GetValue(SelectionsProperty); }
  47. set { this.SetValue(SelectionsProperty, value); }
  48. }
  49. protected override void OnAttached()
  50. {
  51. base.OnAttached();
  52. this.AssociatedObject.SelectionChanged += this.OnSelectedItemsChanged;
  53. this.UpdateSelectedItems();
  54. }
  55. protected override void OnDetaching()
  56. {
  57. this.AssociatedObject.SelectionChanged += this.OnSelectedItemsChanged;
  58. base.OnDetaching();
  59. }
  60. private static void OnSelectionsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  61. {
  62. var behavior = d as SynchronizeSelectedItems;
  63. if (behavior != null)
  64. {
  65. if (behavior.currentWeakHandler != null)
  66. {
  67. behavior.currentWeakHandler.Detach();
  68. behavior.currentWeakHandler = null;
  69. }
  70. if (e.NewValue != null)
  71. {
  72. var notifyCollectionChanged = e.NewValue as INotifyCollectionChanged;
  73. if (notifyCollectionChanged != null)
  74. {
  75. behavior.currentWeakHandler =
  76. new WeakEventHandler<SynchronizeSelectedItems, object, NotifyCollectionChangedEventArgs>(
  77. behavior,
  78. (instance, sender, args) => instance.OnSelectionsCollectionChanged(sender, args),
  79. (listener) => notifyCollectionChanged.CollectionChanged -= listener.OnEvent);
  80. notifyCollectionChanged.CollectionChanged += behavior.currentWeakHandler.OnEvent;
  81. }
  82. behavior.UpdateSelectedItems();
  83. }
  84. }
  85. }
  86. private void OnSelectedItemsChanged(object sender, SelectionChangedEventArgs e)
  87. {
  88. this.UpdateSelections(e);
  89. }
  90. private void UpdateSelections(SelectionChangedEventArgs e)
  91. {
  92. this.ExecuteIfNotUpdating(
  93. () =>
  94. {
  95. if (this.Selections != null)
  96. {
  97. foreach (var item in e.AddedItems)
  98. {
  99. this.Selections.Add(item);
  100. }
  101. foreach (var item in e.RemovedItems)
  102. {
  103. this.Selections.Remove(item);
  104. }
  105. }
  106. });
  107. }
  108. private void OnSelectionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  109. {
  110. this.UpdateSelectedItems();
  111. }
  112. private void UpdateSelectedItems()
  113. {
  114. this.ExecuteIfNotUpdating(
  115. () =>
  116. {
  117. if (this.AssociatedObject != null)
  118. {
  119. this.AssociatedObject.SelectedItems.Clear();
  120. foreach (var item in this.Selections ?? new object[0])
  121. {
  122. this.AssociatedObject.SelectedItems.Add(item);
  123. }
  124. }
  125. });
  126. }
  127. private void ExecuteIfNotUpdating(Action execute)
  128. {
  129. if (!this.updating)
  130. {
  131. try
  132. {
  133. this.updating = true;
  134. execute();
  135. }
  136. finally
  137. {
  138. this.updating = false;
  139. }
  140. }
  141. }
  142. }
  143. }