PageRenderTime 4345ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Catel.Extensions.Controls/Catel.Extensions.Controls.NET40/Windows/Controls/TabControl.cs

#
C# | 324 lines | 193 code | 46 blank | 85 comment | 35 complexity | 185e6211df93f67cd083e63254122b5b MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="TabControl.cs" company="Catel development team">
  3. // Copyright (c) 2008 - 2012 Catel development team. All rights reserved.
  4. // </copyright>
  5. // --------------------------------------------------------------------------------------------------------------------
  6. namespace Catel.Windows.Controls
  7. {
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Specialized;
  11. using System.Linq;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Controls.Primitives;
  15. /// <summary>
  16. /// Load behavior of the tabs in the <see cref="TabControl"/>.
  17. /// </summary>
  18. public enum LoadTabItemsBehavior
  19. {
  20. /// <summary>
  21. /// Load the current tab.
  22. /// </summary>
  23. Single,
  24. /// <summary>
  25. /// Load all when a tab is used for the first time.
  26. /// </summary>
  27. AllOnFirstUse,
  28. /// <summary>
  29. /// Load all as soon as the control is loaded.
  30. /// </summary>
  31. AllOnStartUp,
  32. }
  33. /// <summary>
  34. /// TabControl that will not remove the tab items from the visual tree. This way, views can be re-used.
  35. /// </summary>
  36. /// <remarks>
  37. /// This code was originally found at http://eric.burke.name/dotnetmania/2009/04/26/22.09.28.
  38. /// </remarks>
  39. [TemplatePart(Name = "PART_ItemsHolder", Type = typeof (Panel))]
  40. public class TabControl : System.Windows.Controls.TabControl
  41. {
  42. private Panel _itemsHolder;
  43. #if NET
  44. /// <summary>
  45. /// Initializes a new instance of the <see cref="TabControl"/>.class.
  46. /// </summary>
  47. static TabControl()
  48. {
  49. DefaultStyleKeyProperty.OverrideMetadata(typeof(TabControl), new FrameworkPropertyMetadata(typeof(TabControl)));
  50. }
  51. #endif
  52. /// <summary>
  53. /// Initializes a new instance of the <see cref="T:System.Windows.Controls.TabControl"/>.class.
  54. /// </summary>
  55. /// <remarks></remarks>
  56. public TabControl()
  57. {
  58. // this is necessary so that we get the initial databound selected item
  59. ItemContainerGenerator.StatusChanged += OnItemContainerGeneratorStatusChanged;
  60. Loaded += OnTabControlLoaded;
  61. #if !NET
  62. DefaultStyleKey = typeof (TabControl);
  63. #endif
  64. }
  65. /// <summary>
  66. /// Gets or sets the load tab items.
  67. /// <para />
  68. /// The default value is <see cref="LoadTabItemsBehavior.Single"/>.
  69. /// </summary>
  70. /// <value>
  71. /// The load tab items.
  72. /// </value>
  73. public LoadTabItemsBehavior LoadTabItems
  74. {
  75. get { return (LoadTabItemsBehavior)GetValue(LoadTabItemsProperty); }
  76. set { SetValue(LoadTabItemsProperty, value); }
  77. }
  78. /// <summary>
  79. /// Dependency property registration for the <see cref="LoadTabItems"/> property.
  80. /// </summary>
  81. public static readonly DependencyProperty LoadTabItemsProperty = DependencyProperty.Register("LoadTabItems",
  82. typeof(LoadTabItemsBehavior), typeof(TabControl), new PropertyMetadata(LoadTabItemsBehavior.Single));
  83. /// <summary>
  84. /// Called when the tab control is loaded.
  85. /// </summary>
  86. /// <param name="sender">The sender.</param>
  87. /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
  88. private void OnTabControlLoaded(object sender, RoutedEventArgs e)
  89. {
  90. Loaded -= OnTabControlLoaded;
  91. if (LoadTabItems == LoadTabItemsBehavior.AllOnStartUp)
  92. {
  93. UpdateItems();
  94. }
  95. }
  96. /// <summary>
  97. /// If containers are done, generate the selected item.
  98. /// </summary>
  99. /// <param name="sender">The sender.</param>
  100. /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
  101. private void OnItemContainerGeneratorStatusChanged(object sender, EventArgs e)
  102. {
  103. if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
  104. {
  105. ItemContainerGenerator.StatusChanged -= OnItemContainerGeneratorStatusChanged;
  106. UpdateItems();
  107. }
  108. }
  109. /// <summary>
  110. /// Get the ItemsHolder and generate any children.
  111. /// </summary>
  112. public override void OnApplyTemplate()
  113. {
  114. base.OnApplyTemplate();
  115. _itemsHolder = GetTemplateChild("PART_ItemsHolder") as Panel;
  116. UpdateItems();
  117. }
  118. /// <summary>
  119. /// When the items change we remove any generated panel children and add any new ones as necessary
  120. /// </summary>
  121. /// <param name="e">The event data for the <see cref="E:System.Windows.Controls.ItemContainerGenerator.ItemsChanged"/> event.</param>
  122. protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
  123. {
  124. base.OnItemsChanged(e);
  125. if (_itemsHolder == null)
  126. {
  127. return;
  128. }
  129. switch (e.Action)
  130. {
  131. case NotifyCollectionChangedAction.Reset:
  132. _itemsHolder.Children.Clear();
  133. break;
  134. case NotifyCollectionChangedAction.Add:
  135. case NotifyCollectionChangedAction.Remove:
  136. if (e.OldItems != null)
  137. {
  138. foreach (var item in e.OldItems)
  139. {
  140. ContentPresenter cp = FindChildContentPresenter(item);
  141. if (cp != null)
  142. {
  143. _itemsHolder.Children.Remove(cp);
  144. }
  145. }
  146. }
  147. // don't do anything with new items because we don't want to
  148. // create visuals that aren't being shown
  149. UpdateItems();
  150. break;
  151. case NotifyCollectionChangedAction.Replace:
  152. throw new NotImplementedException("Replace not implemented yet");
  153. }
  154. }
  155. /// <summary>
  156. /// Update the visible child in the ItemsHolder.
  157. /// </summary>
  158. /// <param name="e"></param>
  159. protected override void OnSelectionChanged(SelectionChangedEventArgs e)
  160. {
  161. base.OnSelectionChanged(e);
  162. UpdateItems();
  163. }
  164. /// <summary>
  165. /// Generate a ContentPresenter for every item.
  166. /// </summary>
  167. private void UpdateItems()
  168. {
  169. if (_itemsHolder == null)
  170. {
  171. return;
  172. }
  173. foreach (var item in LoadTabItems >= LoadTabItemsBehavior.AllOnFirstUse ? (IEnumerable)Items : new[] { GetSelectedTabItem() })
  174. {
  175. // generate a ContentPresenter if necessary
  176. if (item != null)
  177. {
  178. CreateChildContentPresenter(item);
  179. }
  180. }
  181. var unvisible = LoadTabItems >= LoadTabItemsBehavior.AllOnFirstUse ? Visibility.Hidden : Visibility.Collapsed;
  182. // show the right child
  183. foreach (ContentPresenter child in _itemsHolder.Children)
  184. {
  185. var tabItem = child.Tag as TabItem;
  186. if (tabItem != null && tabItem.IsSelected)
  187. {
  188. child.Visibility = Visibility.Visible;
  189. }
  190. else
  191. {
  192. child.Visibility = unvisible;
  193. }
  194. }
  195. }
  196. /// <summary>
  197. /// Create the child ContentPresenter for the given item (could be data or a TabItem)
  198. /// </summary>
  199. /// <param name="item">The item.</param>
  200. /// <returns></returns>
  201. private ContentPresenter CreateChildContentPresenter(object item)
  202. {
  203. if (item == null)
  204. {
  205. return null;
  206. }
  207. ContentPresenter cp = FindChildContentPresenter(item);
  208. if (cp != null)
  209. {
  210. return cp;
  211. }
  212. // the actual child to be added. cp.Tag is a reference to the TabItem
  213. cp = new ContentPresenter();
  214. if (item is TabItem)
  215. {
  216. cp.Content = (item as TabItem).Content;
  217. }
  218. else
  219. {
  220. cp.Content = item;
  221. }
  222. cp.ContentTemplate = SelectedContentTemplate;
  223. cp.ContentTemplateSelector = SelectedContentTemplateSelector;
  224. cp.ContentStringFormat = SelectedContentStringFormat;
  225. cp.Visibility = Visibility.Collapsed;
  226. if (item is TabItem)
  227. {
  228. cp.Tag = item;
  229. }
  230. else
  231. {
  232. cp.Tag = ItemContainerGenerator.ContainerFromItem(item);
  233. }
  234. _itemsHolder.Children.Add(cp);
  235. return cp;
  236. }
  237. /// <summary>
  238. /// Find the CP for the given object. data could be a TabItem or a piece of data.
  239. /// </summary>
  240. /// <param name="data">The data.</param>
  241. /// <returns></returns>
  242. private ContentPresenter FindChildContentPresenter(object data)
  243. {
  244. if (data == null)
  245. {
  246. return null;
  247. }
  248. var dataAsTabItem = data as TabItem;
  249. if (dataAsTabItem != null)
  250. {
  251. data = dataAsTabItem.Content;
  252. }
  253. if (_itemsHolder == null)
  254. {
  255. return null;
  256. }
  257. return _itemsHolder.Children.Cast<ContentPresenter>().FirstOrDefault(cp => cp.Content == data);
  258. }
  259. /// <summary>
  260. /// Copied from TabControl; wish it were protected in that class instead of private.
  261. /// </summary>
  262. /// <returns></returns>
  263. protected TabItem GetSelectedTabItem()
  264. {
  265. object selectedItem = SelectedItem;
  266. if (selectedItem == null)
  267. {
  268. return null;
  269. }
  270. var item = selectedItem as TabItem;
  271. if (item == null)
  272. {
  273. item = ItemContainerGenerator.ContainerFromIndex(SelectedIndex) as TabItem;
  274. }
  275. return item;
  276. }
  277. }
  278. }