PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-toolkit/Microsoft.Phone.Controls.Toolkit/DateTimePickers/DateTimePickerPageBase.cs

https://bitbucket.org/jeremejevs/milk-manager
C# | 310 lines | 217 code | 32 blank | 61 comment | 53 complexity | 0c0cf9e650255003f9c2bc2e1fcff8dd 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.Generic;
  7. using System.ComponentModel;
  8. using System.Diagnostics;
  9. using System.Linq;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Media;
  13. using System.Windows.Media.Animation;
  14. using System.Windows.Navigation;
  15. using Microsoft.Phone.Shell;
  16. namespace Microsoft.Phone.Controls.Primitives
  17. {
  18. /// <summary>
  19. /// Represents a base class for pages that work with DateTimePickerBase to allow users to choose a date/time.
  20. /// </summary>
  21. public abstract class DateTimePickerPageBase : PhoneApplicationPage, IDateTimePickerPage
  22. {
  23. private const string VisibilityGroupName = "VisibilityStates";
  24. private const string OpenVisibilityStateName = "Open";
  25. private const string ClosedVisibilityStateName = "Closed";
  26. private const string StateKey_Value = "DateTimePickerPageBase_State_Value";
  27. private LoopingSelector _primarySelectorPart;
  28. private LoopingSelector _secondarySelectorPart;
  29. private LoopingSelector _tertiarySelectorPart;
  30. private Storyboard _closedStoryboard;
  31. /// <summary>
  32. /// Initializes the DateTimePickerPageBase class; must be called from the subclass's constructor.
  33. /// </summary>
  34. /// <param name="primarySelector">Primary selector.</param>
  35. /// <param name="secondarySelector">Secondary selector.</param>
  36. /// <param name="tertiarySelector">Tertiary selector.</param>
  37. protected void InitializeDateTimePickerPage(LoopingSelector primarySelector, LoopingSelector secondarySelector, LoopingSelector tertiarySelector)
  38. {
  39. if (null == primarySelector)
  40. {
  41. throw new ArgumentNullException("primarySelector");
  42. }
  43. if (null == secondarySelector)
  44. {
  45. throw new ArgumentNullException("secondarySelector");
  46. }
  47. if (null == tertiarySelector)
  48. {
  49. throw new ArgumentNullException("tertiarySelector");
  50. }
  51. _primarySelectorPart = primarySelector;
  52. _secondarySelectorPart = secondarySelector;
  53. _tertiarySelectorPart = tertiarySelector;
  54. // Hook up to interesting events
  55. _primarySelectorPart.DataSource.SelectionChanged += OnDataSourceSelectionChanged;
  56. _secondarySelectorPart.DataSource.SelectionChanged += OnDataSourceSelectionChanged;
  57. _tertiarySelectorPart.DataSource.SelectionChanged += OnDataSourceSelectionChanged;
  58. _primarySelectorPart.IsExpandedChanged += OnSelectorIsExpandedChanged;
  59. _secondarySelectorPart.IsExpandedChanged += OnSelectorIsExpandedChanged;
  60. _tertiarySelectorPart.IsExpandedChanged += OnSelectorIsExpandedChanged;
  61. // Hide all selectors
  62. _primarySelectorPart.Visibility = Visibility.Collapsed;
  63. _secondarySelectorPart.Visibility = Visibility.Collapsed;
  64. _tertiarySelectorPart.Visibility = Visibility.Collapsed;
  65. // Position and reveal the culture-relevant selectors
  66. int column = 0;
  67. foreach (LoopingSelector selector in GetSelectorsOrderedByCulturePattern())
  68. {
  69. Grid.SetColumn(selector, column);
  70. selector.Visibility = Visibility.Visible;
  71. column++;
  72. }
  73. // Hook up to storyboard(s)
  74. FrameworkElement templateRoot = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
  75. if (null != templateRoot)
  76. {
  77. foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(templateRoot))
  78. {
  79. if (VisibilityGroupName == group.Name)
  80. {
  81. foreach (VisualState state in group.States)
  82. {
  83. if ((ClosedVisibilityStateName == state.Name) && (null != state.Storyboard))
  84. {
  85. _closedStoryboard = state.Storyboard;
  86. _closedStoryboard.Completed += OnClosedStoryboardCompleted;
  87. }
  88. }
  89. }
  90. }
  91. }
  92. // Customize the ApplicationBar Buttons by providing the right text
  93. if (null != ApplicationBar)
  94. {
  95. foreach (object obj in ApplicationBar.Buttons)
  96. {
  97. IApplicationBarIconButton button = obj as IApplicationBarIconButton;
  98. if (null != button)
  99. {
  100. if ("DONE" == button.Text)
  101. {
  102. button.Text = LocalizedResources.ControlResources.DateTimePickerDoneText;
  103. button.Click += OnDoneButtonClick;
  104. }
  105. else if ("CANCEL" == button.Text)
  106. {
  107. button.Text = LocalizedResources.ControlResources.DateTimePickerCancelText;
  108. button.Click += OnCancelButtonClick;
  109. }
  110. }
  111. }
  112. }
  113. // Play the Open state
  114. VisualStateManager.GoToState(this, OpenVisibilityStateName, true);
  115. }
  116. private void OnDataSourceSelectionChanged(object sender, SelectionChangedEventArgs e)
  117. {
  118. // Push the selected item to all selectors
  119. DataSource dataSource = (DataSource)sender;
  120. _primarySelectorPart.DataSource.SelectedItem = dataSource.SelectedItem;
  121. _secondarySelectorPart.DataSource.SelectedItem = dataSource.SelectedItem;
  122. _tertiarySelectorPart.DataSource.SelectedItem = dataSource.SelectedItem;
  123. }
  124. private void OnSelectorIsExpandedChanged(object sender, DependencyPropertyChangedEventArgs e)
  125. {
  126. if ((bool)e.NewValue)
  127. {
  128. // Ensure that only one selector is expanded at a time
  129. _primarySelectorPart.IsExpanded = (sender == _primarySelectorPart);
  130. _secondarySelectorPart.IsExpanded = (sender == _secondarySelectorPart);
  131. _tertiarySelectorPart.IsExpanded = (sender == _tertiarySelectorPart);
  132. }
  133. }
  134. private void OnDoneButtonClick(object sender, EventArgs e)
  135. {
  136. // Commit the value and close
  137. Debug.Assert((_primarySelectorPart.DataSource.SelectedItem == _secondarySelectorPart.DataSource.SelectedItem) && (_secondarySelectorPart.DataSource.SelectedItem == _tertiarySelectorPart.DataSource.SelectedItem));
  138. _value = ((DateTimeWrapper)_primarySelectorPart.DataSource.SelectedItem).DateTime;
  139. ClosePickerPage();
  140. }
  141. private void OnCancelButtonClick(object sender, EventArgs e)
  142. {
  143. // Close without committing a value
  144. _value = null;
  145. ClosePickerPage();
  146. }
  147. /// <summary>
  148. /// Called when the Back key is pressed.
  149. /// </summary>
  150. /// <param name="e">Event arguments.</param>
  151. protected override void OnBackKeyPress(CancelEventArgs e)
  152. {
  153. if (null == e)
  154. {
  155. throw new ArgumentNullException("e");
  156. }
  157. // Cancel back action so we can play the Close state animation (then go back)
  158. e.Cancel = true;
  159. ClosePickerPage();
  160. }
  161. private void ClosePickerPage()
  162. {
  163. // Play the Close state (if available)
  164. if (null != _closedStoryboard)
  165. {
  166. VisualStateManager.GoToState(this, ClosedVisibilityStateName, true);
  167. }
  168. else
  169. {
  170. OnClosedStoryboardCompleted(null, null);
  171. }
  172. }
  173. private void OnClosedStoryboardCompleted(object sender, EventArgs e)
  174. {
  175. // Close the picker page
  176. NavigationService.GoBack();
  177. }
  178. /// <summary>
  179. /// Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
  180. /// </summary>
  181. /// <returns>LoopingSelectors ordered by culture-specific priority.</returns>
  182. protected abstract IEnumerable<LoopingSelector> GetSelectorsOrderedByCulturePattern();
  183. /// <summary>
  184. /// Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
  185. /// </summary>
  186. /// <param name="pattern">Culture-specific date/time format string.</param>
  187. /// <param name="patternCharacters">Date/time format string characters for the primary/secondary/tertiary LoopingSelectors.</param>
  188. /// <param name="selectors">Instances for the primary/secondary/tertiary LoopingSelectors.</param>
  189. /// <returns>LoopingSelectors ordered by culture-specific priority.</returns>
  190. protected static IEnumerable<LoopingSelector> GetSelectorsOrderedByCulturePattern(string pattern, char[] patternCharacters, LoopingSelector[] selectors)
  191. {
  192. if (null == pattern)
  193. {
  194. throw new ArgumentNullException("pattern");
  195. }
  196. if (null == patternCharacters)
  197. {
  198. throw new ArgumentNullException("patternCharacters");
  199. }
  200. if (null == selectors)
  201. {
  202. throw new ArgumentNullException("selectors");
  203. }
  204. if (patternCharacters.Length != selectors.Length)
  205. {
  206. throw new ArgumentException("Arrays must contain the same number of elements.");
  207. }
  208. // Create a list of index and selector pairs
  209. List<Tuple<int, LoopingSelector>> pairs = new List<Tuple<int, LoopingSelector>>(patternCharacters.Length);
  210. for (int i = 0; i < patternCharacters.Length; i++)
  211. {
  212. pairs.Add(new Tuple<int, LoopingSelector>(pattern.IndexOf(patternCharacters[i]), selectors[i]));
  213. }
  214. // Return the corresponding selectors in order
  215. return pairs.Where(p => -1 != p.Item1).OrderBy(p => p.Item1).Select(p => p.Item2).Where(s => null != s);
  216. }
  217. /// <summary>
  218. /// Gets or sets the DateTime to show in the picker page and to set when the user makes a selection.
  219. /// </summary>
  220. public DateTime? Value
  221. {
  222. get { return _value; }
  223. set
  224. {
  225. _value = value;
  226. DateTimeWrapper wrapper = new DateTimeWrapper(_value.GetValueOrDefault(DateTime.Now));
  227. _primarySelectorPart.DataSource.SelectedItem = wrapper;
  228. _secondarySelectorPart.DataSource.SelectedItem = wrapper;
  229. _tertiarySelectorPart.DataSource.SelectedItem = wrapper;
  230. }
  231. }
  232. private DateTime? _value;
  233. /// <summary>
  234. /// Called when a page is no longer the active page in a frame.
  235. /// </summary>
  236. /// <param name="e">An object that contains the event data.</param>
  237. protected override void OnNavigatedFrom(NavigationEventArgs e)
  238. {
  239. if (null == e)
  240. {
  241. throw new ArgumentNullException("e");
  242. }
  243. base.OnNavigatedFrom(e);
  244. // Save Value if navigating away from application
  245. if ("app://external/" == e.Uri.ToString())
  246. {
  247. State[StateKey_Value] = Value;
  248. }
  249. }
  250. /// <summary>
  251. /// Called when a page becomes the active page in a frame.
  252. /// </summary>
  253. /// <param name="e">An object that contains the event data.</param>
  254. protected override void OnNavigatedTo(NavigationEventArgs e)
  255. {
  256. if (null == e)
  257. {
  258. throw new ArgumentNullException("e");
  259. }
  260. base.OnNavigatedTo(e);
  261. // Restore Value if returning to application (to avoid inconsistent state)
  262. if (State.ContainsKey(StateKey_Value))
  263. {
  264. Value = State[StateKey_Value] as DateTime?;
  265. // Back out from picker page for consistency with behavior of core pickers in this scenario
  266. if (NavigationService.CanGoBack)
  267. {
  268. NavigationService.GoBack();
  269. }
  270. }
  271. }
  272. /// <summary>
  273. /// Sets the selectors and title flow direction.
  274. /// </summary>
  275. /// <param name="flowDirection">Flow direction to set.</param>
  276. internal abstract void SetFlowDirection(FlowDirection flowDirection);
  277. }
  278. }