Advertisement
Guest User

DateTimePickerPageBase.cs

a guest
Jan 2nd, 2014
426
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.72 KB | None | 0 0
  1. using Microsoft.Phone.Controls;
  2. using Microsoft.Phone.Controls.LocalizedResources;
  3. using Microsoft.Phone.Controls.Primitives;
  4. using Microsoft.Phone.Shell;
  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.  
  16. namespace CustomDatePicker.Classes
  17. {
  18.     public abstract class DateTimePickerPageBase : PhoneApplicationPage, IDateTimePickerPage
  19.     {
  20.         private const string VisibilityGroupName = "VisibilityStates";
  21.         private const string OpenVisibilityStateName = "Open";
  22.         private const string ClosedVisibilityStateName = "Closed";
  23.         private const string StateKey_Value = "DateTimePickerPageBase_State_Value";
  24.  
  25.         private LoopingSelector _primarySelectorPart;
  26.         private LoopingSelector _secondarySelectorPart;
  27.         private Storyboard _closedStoryboard;
  28.  
  29.         /// <summary>
  30.         /// Initializes the DateTimePickerPageBase class; must be called from the subclass's constructor.
  31.         /// </summary>
  32.         /// <param name="primarySelector">Primary selector.</param>
  33.         /// <param name="secondarySelector">Secondary selector.</param>
  34.         /// <param name="tertiarySelector">Tertiary selector.</param>
  35.         protected void InitializeDateTimePickerPage(LoopingSelector primarySelector, LoopingSelector secondarySelector)
  36.         {
  37.             if (null == primarySelector)
  38.             {
  39.                 throw new ArgumentNullException("primarySelector");
  40.             }
  41.             if (null == secondarySelector)
  42.             {
  43.                 throw new ArgumentNullException("secondarySelector");
  44.             }
  45.  
  46.             _primarySelectorPart = primarySelector;
  47.             _secondarySelectorPart = secondarySelector;
  48.  
  49.             // Hook up to interesting events
  50.             _primarySelectorPart.DataSource.SelectionChanged += OnDataSourceSelectionChanged;
  51.             _secondarySelectorPart.DataSource.SelectionChanged += OnDataSourceSelectionChanged;
  52.             _primarySelectorPart.IsExpandedChanged += OnSelectorIsExpandedChanged;
  53.             _secondarySelectorPart.IsExpandedChanged += OnSelectorIsExpandedChanged;
  54.  
  55.             // Hide all selectors
  56.             _primarySelectorPart.Visibility = Visibility.Collapsed;
  57.             _secondarySelectorPart.Visibility = Visibility.Collapsed;
  58.  
  59.             // Position and reveal the culture-relevant selectors
  60.             int column = 0;
  61.             foreach (LoopingSelector selector in GetSelectorsOrderedByCulturePattern())
  62.             {
  63.                 Grid.SetColumn(selector, column);
  64.                 selector.Visibility = Visibility.Visible;
  65.                 column++;
  66.             }
  67.  
  68.             // Hook up to storyboard(s)
  69.             FrameworkElement templateRoot = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
  70.             if (null != templateRoot)
  71.             {
  72.                 foreach (VisualStateGroup group in VisualStateManager.GetVisualStateGroups(templateRoot))
  73.                 {
  74.                     if (VisibilityGroupName == group.Name)
  75.                     {
  76.                         foreach (VisualState state in group.States)
  77.                         {
  78.                             if ((ClosedVisibilityStateName == state.Name) && (null != state.Storyboard))
  79.                             {
  80.                                 _closedStoryboard = state.Storyboard;
  81.                                 _closedStoryboard.Completed += OnClosedStoryboardCompleted;
  82.                             }
  83.                         }
  84.                     }
  85.                 }
  86.             }
  87.  
  88.             // Customize the ApplicationBar Buttons by providing the right text
  89.             if (null != ApplicationBar)
  90.             {
  91.                 foreach (object obj in ApplicationBar.Buttons)
  92.                 {
  93.                     IApplicationBarIconButton button = obj as IApplicationBarIconButton;
  94.                     if (null != button)
  95.                     {
  96.                         if ("DONE" == button.Text)
  97.                         {
  98.                             button.Text = ControlResources.DateTimePickerDoneText;
  99.                             button.Click += OnDoneButtonClick;
  100.                         }
  101.                         else if ("CANCEL" == button.Text)
  102.                         {
  103.                             button.Text = ControlResources.DateTimePickerCancelText;
  104.                             button.Click += OnCancelButtonClick;
  105.                         }
  106.                     }
  107.                 }
  108.             }
  109.  
  110.             // Play the Open state
  111.             VisualStateManager.GoToState(this, OpenVisibilityStateName, true);
  112.         }
  113.  
  114.         private void OnDataSourceSelectionChanged(object sender, SelectionChangedEventArgs e)
  115.         {
  116.             // Push the selected item to all selectors
  117.             DataSource dataSource = (DataSource)sender;
  118.             _primarySelectorPart.DataSource.SelectedItem = dataSource.SelectedItem;
  119.             _secondarySelectorPart.DataSource.SelectedItem = dataSource.SelectedItem;
  120.         }
  121.  
  122.         private void OnSelectorIsExpandedChanged(object sender, DependencyPropertyChangedEventArgs e)
  123.         {
  124.             if ((bool)e.NewValue)
  125.             {
  126.                 // Ensure that only one selector is expanded at a time
  127.                 _primarySelectorPart.IsExpanded = (sender == _primarySelectorPart);
  128.                 _secondarySelectorPart.IsExpanded = (sender == _secondarySelectorPart);
  129.             }
  130.         }
  131.  
  132.         private void OnDoneButtonClick(object sender, EventArgs e)
  133.         {
  134.             // Commit the value and close
  135.             Debug.Assert((_primarySelectorPart.DataSource.SelectedItem == _secondarySelectorPart.DataSource.SelectedItem));
  136.             _value = ((DateTimeWrapper)_primarySelectorPart.DataSource.SelectedItem).DateTime;
  137.             ClosePickerPage();
  138.         }
  139.  
  140.         private void OnCancelButtonClick(object sender, EventArgs e)
  141.         {
  142.             // Close without committing a value
  143.             _value = null;
  144.             ClosePickerPage();
  145.         }
  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.  
  158.             // Cancel back action so we can play the Close state animation (then go back)
  159.             e.Cancel = true;
  160.             ClosePickerPage();
  161.         }
  162.  
  163.         private void ClosePickerPage()
  164.         {
  165.             // Play the Close state (if available)
  166.             if (null != _closedStoryboard)
  167.             {
  168.                 VisualStateManager.GoToState(this, ClosedVisibilityStateName, true);
  169.             }
  170.             else
  171.             {
  172.                 OnClosedStoryboardCompleted(null, null);
  173.             }
  174.         }
  175.  
  176.         private void OnClosedStoryboardCompleted(object sender, EventArgs e)
  177.         {
  178.             // Close the picker page
  179.             NavigationService.GoBack();
  180.         }
  181.  
  182.         /// <summary>
  183.         /// Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
  184.         /// </summary>
  185.         /// <returns>LoopingSelectors ordered by culture-specific priority.</returns>
  186.         protected abstract IEnumerable<LoopingSelector> GetSelectorsOrderedByCulturePattern();
  187.  
  188.         /// <summary>
  189.         /// Gets a sequence of LoopingSelector parts ordered according to culture string for date/time formatting.
  190.         /// </summary>
  191.         /// <param name="pattern">Culture-specific date/time format string.</param>
  192.         /// <param name="patternCharacters">Date/time format string characters for the primary/secondary/tertiary LoopingSelectors.</param>
  193.         /// <param name="selectors">Instances for the primary/secondary/tertiary LoopingSelectors.</param>
  194.         /// <returns>LoopingSelectors ordered by culture-specific priority.</returns>
  195.         protected static IEnumerable<LoopingSelector> GetSelectorsOrderedByCulturePattern(string pattern, char[] patternCharacters, LoopingSelector[] selectors)
  196.         {
  197.             if (null == pattern)
  198.             {
  199.                 throw new ArgumentNullException("pattern");
  200.             }
  201.             if (null == patternCharacters)
  202.             {
  203.                 throw new ArgumentNullException("patternCharacters");
  204.             }
  205.             if (null == selectors)
  206.             {
  207.                 throw new ArgumentNullException("selectors");
  208.             }
  209.             if (patternCharacters.Length != selectors.Length)
  210.             {
  211.                 throw new ArgumentException("Arrays must contain the same number of elements.");
  212.             }
  213.  
  214.             // Create a list of index and selector pairs
  215.             List<Tuple<int, LoopingSelector>> pairs = new List<Tuple<int, LoopingSelector>>(patternCharacters.Length);
  216.             for (int i = 0; i < patternCharacters.Length; i++)
  217.             {
  218.                 pairs.Add(new Tuple<int, LoopingSelector>(pattern.IndexOf(patternCharacters[i]), selectors[i]));
  219.             }
  220.  
  221.             // Return the corresponding selectors in order
  222.             return pairs.Where(p => -1 != p.Item1).OrderBy(p => p.Item1).Select(p => p.Item2).Where(s => null != s);
  223.         }
  224.  
  225.         /// <summary>
  226.         /// Gets or sets the DateTime to show in the picker page and to set when the user makes a selection.
  227.         /// </summary>
  228.         public DateTime? Value
  229.         {
  230.             get { return _value; }
  231.             set
  232.             {
  233.                 _value = value;
  234.                 DateTimeWrapper wrapper = new DateTimeWrapper(_value.GetValueOrDefault(DateTime.Now));
  235.                 _primarySelectorPart.DataSource.SelectedItem = wrapper;
  236.                 _secondarySelectorPart.DataSource.SelectedItem = wrapper;
  237.             }
  238.         }
  239.         private DateTime? _value;
  240.  
  241.         /// <summary>
  242.         /// Called when a page is no longer the active page in a frame.
  243.         /// </summary>
  244.         /// <param name="e">An object that contains the event data.</param>
  245.         protected override void OnNavigatedFrom(NavigationEventArgs e)
  246.         {
  247.             if (null == e)
  248.             {
  249.                 throw new ArgumentNullException("e");
  250.             }
  251.  
  252.             base.OnNavigatedFrom(e);
  253.  
  254.             // Save Value if navigating away from application
  255.             if ("app://external/" == e.Uri.ToString())
  256.             {
  257.                 State[StateKey_Value] = Value;
  258.             }
  259.         }
  260.  
  261.         /// <summary>
  262.         /// Called when a page becomes the active page in a frame.
  263.         /// </summary>
  264.         /// <param name="e">An object that contains the event data.</param>
  265.         protected override void OnNavigatedTo(NavigationEventArgs e)
  266.         {
  267.             if (null == e)
  268.             {
  269.                 throw new ArgumentNullException("e");
  270.             }
  271.  
  272.             base.OnNavigatedTo(e);
  273.  
  274.             // Restore Value if returning to application (to avoid inconsistent state)
  275.             if (State.ContainsKey(StateKey_Value))
  276.             {
  277.                 Value = State[StateKey_Value] as DateTime?;
  278.  
  279.                 // Back out from picker page for consistency with behavior of core pickers in this scenario
  280.                 if (NavigationService.CanGoBack)
  281.                 {
  282.                     NavigationService.GoBack();
  283.                 }
  284.             }
  285.         }
  286.  
  287.         /// <summary>
  288.         /// Sets the selectors and title flow direction.
  289.         /// </summary>
  290.         /// <param name="flowDirection">Flow direction to set.</param>
  291.         internal abstract void SetFlowDirection(FlowDirection flowDirection);
  292.  
  293.         void IDateTimePickerPage.SetFlowDirection(FlowDirection flowDirection)
  294.         {
  295.             SetFlowDirection(flowDirection);
  296.         }
  297.     }
  298.  
  299.     abstract class DataSource : ILoopingSelectorDataSource
  300.     {
  301.         private DateTimeWrapper _selectedItem;
  302.  
  303.         public object GetNext(object relativeTo)
  304.         {
  305.             DateTime? next = GetRelativeTo(((DateTimeWrapper)relativeTo).DateTime, 1);
  306.             return next.HasValue ? new DateTimeWrapper(next.Value) : null;
  307.         }
  308.  
  309.         public object GetPrevious(object relativeTo)
  310.         {
  311.             DateTime? next = GetRelativeTo(((DateTimeWrapper)relativeTo).DateTime, -1);
  312.             return next.HasValue ? new DateTimeWrapper(next.Value) : null;
  313.         }
  314.  
  315.         protected abstract DateTime? GetRelativeTo(DateTime relativeDate, int delta);
  316.  
  317.         public object SelectedItem
  318.         {
  319.             get { return _selectedItem; }
  320.             set
  321.             {
  322.                 if (value != _selectedItem)
  323.                 {
  324.                     DateTimeWrapper valueWrapper = (DateTimeWrapper)value;
  325.                     if ((null == valueWrapper) || (null == _selectedItem) || (valueWrapper.DateTime != _selectedItem.DateTime))
  326.                     {
  327.                         object previousSelectedItem = _selectedItem;
  328.                         _selectedItem = valueWrapper;
  329.                         var handler = SelectionChanged;
  330.                         if (null != handler)
  331.                         {
  332.                             handler(this, new SelectionChangedEventArgs(new object[] { previousSelectedItem }, new object[] { _selectedItem }));
  333.                         }
  334.                     }
  335.                 }
  336.             }
  337.         }
  338.  
  339.         public event EventHandler<SelectionChangedEventArgs> SelectionChanged;
  340.     }
  341.  
  342.     class YearDataSource : DataSource
  343.     {
  344.         protected override DateTime? GetRelativeTo(DateTime relativeDate, int delta)
  345.         {
  346.             if ((1601 == relativeDate.Year) || (3000 == relativeDate.Year))
  347.             {
  348.                 return null;
  349.             }
  350.             int nextYear = relativeDate.Year + delta;
  351.             int nextDay = Math.Min(relativeDate.Day, DateTime.DaysInMonth(nextYear, relativeDate.Month));
  352.             return new DateTime(nextYear, relativeDate.Month, nextDay, relativeDate.Hour, relativeDate.Minute, relativeDate.Second);
  353.         }
  354.     }
  355.  
  356.     class MonthDataSource : DataSource
  357.     {
  358.         protected override DateTime? GetRelativeTo(DateTime relativeDate, int delta)
  359.         {
  360.             int monthsInYear = 12;
  361.             int nextMonth = ((monthsInYear + relativeDate.Month - 1 + delta) % monthsInYear) + 1;
  362.             int nextDay = Math.Min(relativeDate.Day, DateTime.DaysInMonth(relativeDate.Year, nextMonth));
  363.             return new DateTime(relativeDate.Year, nextMonth, nextDay, relativeDate.Hour, relativeDate.Minute, relativeDate.Second);
  364.         }
  365.     }
  366. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement