PageRenderTime 42ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-toolkit/Microsoft.Phone.Controls.Toolkit/MultiselectList/MultiselectList.cs

https://bitbucket.org/jeremejevs/milk-manager
C# | 330 lines | 190 code | 46 blank | 94 comment | 27 complexity | 81141636e9c06ba4f2a6f7cfc19d783c MD5 | raw file
  1. // (c) Copyright Microsoft Corporation.
  2. // This source is subject to the Microsoft Public License (Ms-PL).
  3. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
  4. // All other rights reserved.
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Collections.Specialized;
  9. using System.Diagnostics.CodeAnalysis;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. namespace Microsoft.Phone.Controls
  13. {
  14. /// <summary>
  15. /// A collection of items that supports multiple selection.
  16. /// </summary>
  17. /// <QualityBand>Experimental</QualityBand>
  18. [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(MultiselectList))]
  19. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly")]
  20. public class MultiselectList : ItemsControl
  21. {
  22. /// <summary>
  23. /// Collection of items that are currently selected.
  24. /// </summary>
  25. public IList SelectedItems { get; private set; }
  26. /// <summary>
  27. /// Occurs when there is a change to the SelectedItems collection.
  28. /// </summary>
  29. public event SelectionChangedEventHandler SelectionChanged;
  30. /// <summary>
  31. /// Occurs when the selection mode is opened or closed.
  32. /// </summary>
  33. public event DependencyPropertyChangedEventHandler IsSelectionEnabledChanged;
  34. #region IsSelectionEnabled DependencyProperty
  35. /// <summary>
  36. /// Gets or sets the flag that indicates if the list
  37. /// is in selection mode or not.
  38. /// </summary>
  39. public bool IsSelectionEnabled
  40. {
  41. get { return (bool)GetValue(IsInSelectionModeProperty); }
  42. set { SetValue(IsInSelectionModeProperty, value); }
  43. }
  44. /// <summary>
  45. /// Identifies the IsSelectionEnabled dependency property.
  46. /// </summary>
  47. public static readonly DependencyProperty IsInSelectionModeProperty =
  48. DependencyProperty.Register("IsSelectionEnabled", typeof(bool), typeof(MultiselectList), new PropertyMetadata(false, OnIsSelectionEnabledPropertyChanged));
  49. /// <summary>
  50. /// Opens or closes the selection mode accordingly.
  51. /// If closing, it unselects any selected item.
  52. /// Finally, it fires up an IsSelectionEnabledChanged event.
  53. /// </summary>
  54. /// <param name="obj">The dependency object.</param>
  55. /// <param name="e">The event information.</param>
  56. private static void OnIsSelectionEnabledPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  57. {
  58. MultiselectList target = (MultiselectList)obj;
  59. if ((bool)e.NewValue)
  60. {
  61. target.OpenSelection();
  62. }
  63. else
  64. {
  65. if (target.SelectedItems.Count > 0)
  66. {
  67. IList removedItems = new List<object>();
  68. //All the selected items will be unselected.
  69. foreach (object item in target.SelectedItems)
  70. {
  71. removedItems.Add(item);
  72. }
  73. //Unselect the containers that are not virtualized.
  74. for (int k = 0; k < target.Items.Count && target.SelectedItems.Count > 0; k++)
  75. {
  76. MultiselectItem item = (MultiselectItem)target.ItemContainerGenerator.ContainerFromIndex(k);
  77. if (item != null)
  78. {
  79. if (item.IsSelected == true)
  80. {
  81. item._canTriggerSelectionChanged = false;
  82. item.IsSelected = false;
  83. item._canTriggerSelectionChanged = true;
  84. }
  85. }
  86. }
  87. //Clear the selected items and trigger event.
  88. target.SelectedItems.Clear();
  89. target.OnSelectionChanged(removedItems, new object[0]);
  90. }
  91. target.CloseSelection();
  92. }
  93. var handler = target.IsSelectionEnabledChanged;
  94. if (handler != null)
  95. {
  96. handler(obj, e);
  97. }
  98. }
  99. #endregion
  100. #region ItemInfoTemplate DependencyProperty
  101. /// <summary>
  102. /// Gets or sets the data template that is to be
  103. /// used on the item information field of the MultiselectItems.
  104. /// </summary>
  105. public DataTemplate ItemInfoTemplate
  106. {
  107. get { return (DataTemplate)GetValue(ItemInfoTemplateProperty); }
  108. set { SetValue(ItemInfoTemplateProperty, value); }
  109. }
  110. /// <summary>
  111. /// Identifies the ItemInfoTemplate dependency property.
  112. /// </summary>
  113. public static readonly DependencyProperty ItemInfoTemplateProperty =
  114. DependencyProperty.Register("ItemInfoTemplate", typeof(DataTemplate), typeof(MultiselectList), new PropertyMetadata(null, null));
  115. #endregion
  116. #region ItemContainerStyle DependencyProperty
  117. /// <summary>
  118. /// Gets or sets the item container style.
  119. /// </summary>
  120. public Style ItemContainerStyle
  121. {
  122. get { return (Style)GetValue(ItemContainerStyleProperty); }
  123. set { SetValue(ItemContainerStyleProperty, value); }
  124. }
  125. /// <summary>
  126. /// Identifies the ItemContainerStyle dependency property.
  127. /// </summary>
  128. public static readonly DependencyProperty ItemContainerStyleProperty =
  129. DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(MultiselectList), new PropertyMetadata(null, null));
  130. #endregion
  131. /// <summary>
  132. /// Initializes a new instance of the MultiselectList class.
  133. /// </summary>
  134. public MultiselectList()
  135. {
  136. DefaultStyleKey = typeof(MultiselectList);
  137. SelectedItems = new List<object>();
  138. }
  139. /// <summary>
  140. /// Toogles the selection mode based on the count of selected items,
  141. /// and fires a SelectionChanged event.
  142. /// </summary>
  143. /// <param name="removedItems">
  144. /// A collection containing the items that were unselected.
  145. /// </param>
  146. /// <param name="addedItems">
  147. /// A collection containing the items that were selected.
  148. /// </param>
  149. internal void OnSelectionChanged(IList removedItems, IList addedItems)
  150. {
  151. if (SelectedItems.Count <= 0)
  152. {
  153. IsSelectionEnabled = false;
  154. }
  155. else if (SelectedItems.Count == 1 && removedItems.Count == 0)
  156. {
  157. IsSelectionEnabled = true;
  158. }
  159. var handler = SelectionChanged;
  160. if (handler != null)
  161. {
  162. handler(this, new SelectionChangedEventArgs(removedItems, addedItems));
  163. }
  164. }
  165. /// <summary>
  166. /// Triggers the visual state changes and visual transitions
  167. /// to open the list into selection mode.
  168. /// </summary>
  169. private void OpenSelection()
  170. {
  171. IList<WeakReference> items = ItemsControlExtensions.GetItemsInViewPort(this);
  172. //Only animate the containers in the view port.
  173. foreach (var i in items)
  174. {
  175. MultiselectItem item = (MultiselectItem)(((WeakReference)i).Target);
  176. item.State = SelectionEnabledState.Opened;
  177. item.UpdateVisualState(true);
  178. }
  179. Dispatcher.BeginInvoke(() =>
  180. {
  181. for (int j = 0; j < this.Items.Count; j++)
  182. {
  183. MultiselectItem item = (MultiselectItem)ItemContainerGenerator.ContainerFromIndex(j);
  184. if (item != null)
  185. {
  186. item.State = SelectionEnabledState.Opened;
  187. item.UpdateVisualState(false);
  188. }
  189. }
  190. });
  191. }
  192. /// <summary>
  193. /// Triggers the visual state changes and visual transitions
  194. /// to close the list out of selection mode.
  195. /// </summary>
  196. private void CloseSelection()
  197. {
  198. IList<WeakReference> items = ItemsControlExtensions.GetItemsInViewPort(this);
  199. //Only animate the containers in the view port.
  200. foreach (var i in items)
  201. {
  202. MultiselectItem item = (MultiselectItem)(((WeakReference)i).Target);
  203. item.State = SelectionEnabledState.Closed;
  204. item.UpdateVisualState(true);
  205. }
  206. Dispatcher.BeginInvoke(() =>
  207. {
  208. for (int j = 0; j < this.Items.Count; j++)
  209. {
  210. MultiselectItem item = (MultiselectItem)ItemContainerGenerator.ContainerFromIndex(j);
  211. if (item != null)
  212. {
  213. item.State = SelectionEnabledState.Closed;
  214. item.UpdateVisualState(false);
  215. }
  216. }
  217. });
  218. }
  219. #region ItemsControl overriden methods
  220. /// <summary>
  221. /// Overrides the DependencyObject used by this ItemsControl
  222. /// to be a MultiselectItem.
  223. /// </summary>
  224. /// <returns>
  225. /// A new instance of a MultiselectItem.
  226. /// </returns>
  227. protected override DependencyObject GetContainerForItemOverride()
  228. {
  229. return new MultiselectItem();
  230. }
  231. /// <summary>
  232. /// Acknowledges an item as being of the same type as its container
  233. /// if it is a MultiselectItem.
  234. /// </summary>
  235. /// <param name="item">An item owned by the ItemsControl.</param>
  236. /// <returns>True if the item is a MultiselectItem.</returns>
  237. protected override bool IsItemItsOwnContainerOverride(object item)
  238. {
  239. return (item is MultiselectItem);
  240. }
  241. /// <summary>
  242. /// Resets new or reused item containers appropiately.
  243. /// </summary>
  244. /// <param name="element"></param>
  245. /// <param name="item"></param>
  246. protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
  247. {
  248. base.PrepareContainerForItemOverride(element, item);
  249. MultiselectItem container = (MultiselectItem)element;
  250. container.Style = this.ItemContainerStyle;
  251. container._isBeingVirtualized = true;
  252. //Select or unselect item containers to put or clear checkmarks.
  253. container.IsSelected = SelectedItems.Contains(item);
  254. //Open or close item containers depending on the selection mode.
  255. container.State = IsSelectionEnabled ? SelectionEnabledState.Opened : SelectionEnabledState.Closed;
  256. container.UpdateVisualState(false);
  257. container._isBeingVirtualized = false;
  258. }
  259. /// <summary>
  260. /// Unselects any selected item which was removed from the source.
  261. /// </summary>
  262. /// <param name="e">The event information.</param>
  263. protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
  264. {
  265. base.OnItemsChanged(e);
  266. if (SelectedItems.Count > 0)
  267. {
  268. IList removedItems = new List<object>();
  269. for (int i = 0; i < SelectedItems.Count; i++)
  270. {
  271. var item = SelectedItems[i];
  272. if (!(Items.Contains(item)))
  273. {
  274. SelectedItems.Remove(item);
  275. removedItems.Add(item);
  276. i--;
  277. }
  278. }
  279. OnSelectionChanged(removedItems, new object[0]);
  280. }
  281. }
  282. #endregion
  283. }
  284. }