From ed8ef8c7a9dbbaf519dd343fb3a4161b4d23145d Mon Sep 17 00:00:00 2001
From: NaBian <836904362@qq.com>
Date: Tue, 20 Nov 2018 15:31:10 +0800
Subject: [PATCH] add datetimepicker
---
.../Attach/BackgroundSwitchElement.cs | 1 -
HandyControl/Controls/Attach/BorderElement.cs | 1 -
.../Controls/Attach/DataGridAttach.cs | 1 -
HandyControl/Controls/Attach/TitleElement.cs | 17 +
HandyControl/Controls/Input/DateTimePicker.cs | 690 ++++++++++++++++++
HandyControl/Controls/Input/TimePicker.cs | 61 +-
.../Controls/Time/CalendarWithClock.cs | 260 +++++++
.../Controls/{ => Time}/Clock/Clock.cs | 82 ++-
.../{ => Time}/Clock/ClockRadioButton.cs | 0
.../{ => Time}/TimeBar/SpeTextBlock.cs | 0
.../Controls/{ => Time}/TimeBar/TimeBar.cs | 0
HandyControl/HandyControl.csproj | 23 +-
.../Styles/Base/DateTimePickerBaseStyle.xaml | 338 +++++++++
.../Styles/Base/TimePickerBaseStyle.xaml | 20 +-
HandyControl/Themes/Styles/Calendar.xaml | 7 +-
.../Themes/Styles/CalendarWithClock.xaml | 44 ++
HandyControl/Themes/Styles/Clock.xaml | 9 +-
.../Themes/Styles/DateTimePicker.xaml | 15 +
HandyControl/Themes/Styles/Style.xaml | 2 +
HandyControlDemo/Data/MessageToken.cs | 4 +
HandyControlDemo/Data/MessageToken.tt | 4 +-
HandyControlDemo/HandyControlDemo.csproj | 14 +
.../Properties/Langs/Lang.Designer.cs | 20 +-
.../Properties/Langs/Lang.en.resx | 6 +
HandyControlDemo/Properties/Langs/Lang.resx | 6 +
.../Controls/CalendarWithClockDemoCtl.xaml | 9 +
.../Controls/CalendarWithClockDemoCtl.xaml.cs | 10 +
.../Controls/DatePickerDemoCtl.xaml | 2 +-
.../Controls/DateTimePickerDemoCtl.xaml | 31 +
.../Controls/DateTimePickerDemoCtl.xaml.cs | 10 +
.../Controls/TimePickerDemoCtl.xaml.cs | 6 +-
.../UserControl/Main/LeftMainContent.xaml | 24 +-
32 files changed, 1611 insertions(+), 106 deletions(-)
create mode 100644 HandyControl/Controls/Attach/TitleElement.cs
create mode 100644 HandyControl/Controls/Input/DateTimePicker.cs
create mode 100644 HandyControl/Controls/Time/CalendarWithClock.cs
rename HandyControl/Controls/{ => Time}/Clock/Clock.cs (85%)
rename HandyControl/Controls/{ => Time}/Clock/ClockRadioButton.cs (100%)
rename HandyControl/Controls/{ => Time}/TimeBar/SpeTextBlock.cs (100%)
rename HandyControl/Controls/{ => Time}/TimeBar/TimeBar.cs (100%)
create mode 100644 HandyControl/Themes/Styles/Base/DateTimePickerBaseStyle.xaml
create mode 100644 HandyControl/Themes/Styles/CalendarWithClock.xaml
create mode 100644 HandyControl/Themes/Styles/DateTimePicker.xaml
create mode 100644 HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml
create mode 100644 HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml.cs
create mode 100644 HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml
create mode 100644 HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml.cs
diff --git a/HandyControl/Controls/Attach/BackgroundSwitchElement.cs b/HandyControl/Controls/Attach/BackgroundSwitchElement.cs
index 09da3666..c690435b 100644
--- a/HandyControl/Controls/Attach/BackgroundSwitchElement.cs
+++ b/HandyControl/Controls/Attach/BackgroundSwitchElement.cs
@@ -1,7 +1,6 @@
using System.Windows;
using System.Windows.Media;
-// ReSharper disable once CheckNamespace
namespace HandyControl.Controls
{
public class BackgroundSwitchElement : DependencyObject
diff --git a/HandyControl/Controls/Attach/BorderElement.cs b/HandyControl/Controls/Attach/BorderElement.cs
index 8868c3c2..451095e1 100644
--- a/HandyControl/Controls/Attach/BorderElement.cs
+++ b/HandyControl/Controls/Attach/BorderElement.cs
@@ -1,6 +1,5 @@
using System.Windows;
-// ReSharper disable once CheckNamespace
namespace HandyControl.Controls
{
public class BorderElement : DependencyObject
diff --git a/HandyControl/Controls/Attach/DataGridAttach.cs b/HandyControl/Controls/Attach/DataGridAttach.cs
index 3385ac3d..f122cab3 100644
--- a/HandyControl/Controls/Attach/DataGridAttach.cs
+++ b/HandyControl/Controls/Attach/DataGridAttach.cs
@@ -2,7 +2,6 @@
using System.Windows;
using System.Windows.Controls;
-// ReSharper disable once CheckNamespace
namespace HandyControl.Controls
{
public class DataGridAttach : DependencyObject
diff --git a/HandyControl/Controls/Attach/TitleElement.cs b/HandyControl/Controls/Attach/TitleElement.cs
new file mode 100644
index 00000000..c5a1a711
--- /dev/null
+++ b/HandyControl/Controls/Attach/TitleElement.cs
@@ -0,0 +1,17 @@
+using System.Windows;
+using System.Windows.Media;
+
+namespace HandyControl.Controls
+{
+ public class TitleElement : DependencyObject
+ {
+ public static readonly DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached(
+ "Background", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
+
+ public static void SetBackground(DependencyObject element, Brush value)
+ => element.SetValue(BackgroundProperty, value);
+
+ public static Brush GetBackground(DependencyObject element)
+ => (Brush) element.GetValue(BackgroundProperty);
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Controls/Input/DateTimePicker.cs b/HandyControl/Controls/Input/DateTimePicker.cs
new file mode 100644
index 00000000..c32c83ec
--- /dev/null
+++ b/HandyControl/Controls/Input/DateTimePicker.cs
@@ -0,0 +1,690 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Input;
+using System.Windows.Threading;
+using HandyControl.Data;
+using HandyControl.Interactivity;
+
+namespace HandyControl.Controls
+{
+ ///
+ /// 时间日期选择器
+ ///
+ [TemplatePart(Name = ElementRoot, Type = typeof(Grid))]
+ [TemplatePart(Name = ElementTextBox, Type = typeof(WatermarkTextBox))]
+ [TemplatePart(Name = ElementButton, Type = typeof(Button))]
+ [TemplatePart(Name = ElementPopup, Type = typeof(Popup))]
+ public class DateTimePicker : Control, IDataInput
+ {
+ #region Constants
+
+ private const string ElementRoot = "PART_Root";
+
+ private const string ElementTextBox = "PART_TextBox";
+
+ private const string ElementButton = "PART_Button";
+
+ private const string ElementPopup = "PART_Popup";
+
+ #endregion Constants
+
+ #region Data
+
+ private CalendarWithClock _calendarWithClock;
+
+ private string _defaultText;
+
+ private ButtonBase _dropDownButton;
+
+ private Popup _popUp;
+
+ private bool _disablePopupReopen;
+
+ private WatermarkTextBox _textBox;
+
+ private IDictionary _isHandlerSuspended;
+
+ private DateTime? _originalSelectedDateTime;
+
+ #endregion Data
+
+ #region Public Events
+
+ public static readonly RoutedEvent SelectedDateTimeChangedEvent =
+ EventManager.RegisterRoutedEvent("SelectedDateTimeChanged", RoutingStrategy.Direct,
+ typeof(EventHandler>), typeof(DateTimePicker));
+
+ public event EventHandler> SelectedDateTimeChanged
+ {
+ add => AddHandler(SelectedDateTimeChangedEvent, value);
+ remove => RemoveHandler(SelectedDateTimeChangedEvent, value);
+ }
+
+ public event RoutedEventHandler PickerClosed;
+
+ public event RoutedEventHandler PickerOpened;
+
+ #endregion Public Events
+
+ static DateTimePicker()
+ {
+ EventManager.RegisterClassHandler(typeof(DateTimePicker), GotFocusEvent, new RoutedEventHandler(OnGotFocus));
+ KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(DateTimePicker), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
+ KeyboardNavigation.IsTabStopProperty.OverrideMetadata(typeof(DateTimePicker), new FrameworkPropertyMetadata(false));
+ }
+
+ public DateTimePicker()
+ {
+ InitCalendarWithClock();
+ CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
+ {
+ ClearValue(SelectedDateTimeProperty);
+ ClearValue(TextProperty);
+ _textBox.Text = string.Empty;
+ }));
+ }
+
+ #region Public Properties
+
+ public static readonly DependencyProperty DateTimeFormatProperty = DependencyProperty.Register(
+ "DateTimeFormat", typeof(string), typeof(DateTimePicker), new PropertyMetadata("yyyy-MM-dd HH:mm:ss"));
+
+ public string DateTimeFormat
+ {
+ get => (string) GetValue(DateTimeFormatProperty);
+ set => SetValue(DateTimeFormatProperty, value);
+ }
+
+ public static readonly DependencyProperty ClockStyleProperty = DependencyProperty.Register(
+ "ClockStyle", typeof(Style), typeof(DateTimePicker), new PropertyMetadata(default(Style)));
+
+ public Style ClockStyle
+ {
+ get => (Style) GetValue(ClockStyleProperty);
+ set => SetValue(ClockStyleProperty, value);
+ }
+
+ public static readonly DependencyProperty CalendarStyleProperty = DependencyProperty.Register(
+ "CalendarStyle", typeof(Style), typeof(DateTimePicker), new PropertyMetadata(default(Style)));
+
+ public Style CalendarStyle
+ {
+ get => (Style) GetValue(CalendarStyleProperty);
+ set => SetValue(CalendarStyleProperty, value);
+ }
+
+ public static readonly DependencyProperty DisplayDateTimeProperty = DependencyProperty.Register(
+ "DisplayDateTime", typeof(DateTime), typeof(DateTimePicker), new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, CoerceDisplayDateTime));
+
+ private static object CoerceDisplayDateTime(DependencyObject d, object value)
+ {
+ var dp = (DateTimePicker)d;
+ dp._calendarWithClock.DisplayDateTime = (DateTime)value;
+
+ return dp._calendarWithClock.DisplayDateTime;
+ }
+
+ public DateTime DisplayDateTime
+ {
+ get => (DateTime) GetValue(DisplayDateTimeProperty);
+ set => SetValue(DisplayDateTimeProperty, value);
+ }
+
+ public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
+ "IsDropDownOpen", typeof(bool), typeof(DateTimePicker), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsDropDownOpenChanged, OnCoerceIsDropDownOpen));
+
+ private static object OnCoerceIsDropDownOpen(DependencyObject d, object baseValue) => d is DateTimePicker dp && !dp.IsEnabled ? false : baseValue;
+
+ private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var dp = d as DateTimePicker;
+
+ var newValue = (bool)e.NewValue;
+ if (dp?._popUp != null && dp._popUp.IsOpen != newValue)
+ {
+ dp._popUp.IsOpen = newValue;
+ if (newValue)
+ {
+ dp._originalSelectedDateTime = dp.SelectedDateTime;
+
+ dp.Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate
+ {
+ dp._calendarWithClock.Focus();
+ });
+ }
+
+ }
+ }
+
+ public bool IsDropDownOpen
+ {
+ get => (bool) GetValue(IsDropDownOpenProperty);
+ set => SetValue(IsDropDownOpenProperty, value);
+ }
+
+ public static readonly DependencyProperty SelectedDateTimeProperty = DependencyProperty.Register(
+ "SelectedDateTime", typeof(DateTime?), typeof(DateTimePicker), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedDateTimeChanged, CoerceSelectedDateTime));
+
+ private static object CoerceSelectedDateTime(DependencyObject d, object value)
+ {
+ var dp = (DateTimePicker)d;
+ dp._calendarWithClock.SelectedDateTime = (DateTime?)value;
+ return dp._calendarWithClock.SelectedDateTime;
+ }
+
+ private static void OnSelectedDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (!(d is DateTimePicker dp)) return;
+
+ if (dp.SelectedDateTime.HasValue)
+ {
+ var time = dp.SelectedDateTime.Value;
+ dp.SetTextInternal(dp.DateTimeToString(time));
+ }
+
+ dp.RaiseEvent(new FunctionEventArgs(SelectedDateTimeChangedEvent, dp)
+ {
+ Info = dp.SelectedDateTime
+ });
+ }
+
+ public DateTime? SelectedDateTime
+ {
+ get => (DateTime?) GetValue(SelectedDateTimeProperty);
+ set => SetValue(SelectedDateTimeProperty, value);
+ }
+
+ public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
+ "Text", typeof(string), typeof(DateTimePicker), new FrameworkPropertyMetadata(string.Empty, OnTextChanged));
+
+ private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is DateTimePicker dp && !dp.IsHandlerSuspended(TextProperty))
+ {
+ if (e.NewValue is string newValue)
+ {
+ if (dp._textBox != null)
+ {
+ dp._textBox.Text = newValue;
+ }
+ else
+ {
+ dp._defaultText = newValue;
+ }
+
+ dp.SetSelectedDateTime();
+ }
+ else
+ {
+ dp.SetValueNoCallback(SelectedDateTimeProperty, null);
+ }
+ }
+ }
+
+ public string Text
+ {
+ get => (string) GetValue(TextProperty);
+ set => SetValue(TextProperty, value);
+ }
+
+ ///
+ /// Sets the local Text property without breaking bindings
+ ///
+ ///
+ private void SetTextInternal(string value)
+ {
+ SetCurrentValue(TextProperty, value);
+ }
+
+ public Func> VerifyFunc { get; set; }
+
+ public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
+ "IsError", typeof(bool), typeof(DateTimePicker), new PropertyMetadata(ValueBoxes.FalseBox));
+
+ public bool IsError
+ {
+ get => (bool) GetValue(IsErrorProperty);
+ set => SetValue(IsErrorProperty, value);
+ }
+
+ public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
+ "ErrorStr", typeof(string), typeof(DateTimePicker), new PropertyMetadata(default(string)));
+
+ public string ErrorStr
+ {
+ get => (string) GetValue(ErrorStrProperty);
+ set => SetValue(ErrorStrProperty, value);
+ }
+
+ public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
+ "TextType", typeof(TextType), typeof(DateTimePicker), new PropertyMetadata(default(TextType)));
+
+ public TextType TextType
+ {
+ get => (TextType) GetValue(TextTypeProperty);
+ set => SetValue(TextTypeProperty, value);
+ }
+
+ public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
+ "ShowClearButton", typeof(bool), typeof(DateTimePicker), new PropertyMetadata(ValueBoxes.FalseBox));
+
+ public bool ShowClearButton
+ {
+ get => (bool) GetValue(ShowClearButtonProperty);
+ set => SetValue(ShowClearButtonProperty, value);
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public override void OnApplyTemplate()
+ {
+ if (DesignerProperties.GetIsInDesignMode(this)) return;
+ if (_popUp != null)
+ {
+ _popUp.PreviewMouseLeftButtonDown -= PopUp_PreviewMouseLeftButtonDown;
+ _popUp.Opened -= PopUp_Opened;
+ _popUp.Closed -= PopUp_Closed;
+ _popUp.Child = null;
+ }
+
+ if (_dropDownButton != null)
+ {
+ _dropDownButton.Click -= DropDownButton_Click;
+ _dropDownButton.MouseLeave -= DropDownButton_MouseLeave;
+ }
+
+ if (_textBox != null)
+ {
+ _textBox.KeyDown -= TextBox_KeyDown;
+ _textBox.TextChanged -= TextBox_TextChanged;
+ _textBox.LostFocus -= TextBox_LostFocus;
+ }
+
+ base.OnApplyTemplate();
+
+ _popUp = GetTemplateChild(ElementPopup) as Popup;
+ _dropDownButton = GetTemplateChild(ElementButton) as Button;
+ _textBox = GetTemplateChild(ElementTextBox) as WatermarkTextBox;
+
+ CheckNull();
+
+ _popUp.PreviewMouseLeftButtonDown += PopUp_PreviewMouseLeftButtonDown;
+ _popUp.Opened += PopUp_Opened;
+ _popUp.Closed += PopUp_Closed;
+ _popUp.Child = _calendarWithClock;
+
+ if (IsDropDownOpen)
+ {
+ _popUp.IsOpen = true;
+ }
+
+ _dropDownButton.Click += DropDownButton_Click;
+ _dropDownButton.MouseLeave += DropDownButton_MouseLeave;
+ if (SelectedDateTime == null)
+ {
+ _textBox.Text = DateTime.Now.ToString(DateTimeFormat);
+ }
+ _textBox.KeyDown += TextBox_KeyDown;
+ _textBox.TextChanged += TextBox_TextChanged;
+ _textBox.LostFocus += TextBox_LostFocus;
+
+ if (SelectedDateTime == null)
+ {
+ if (!string.IsNullOrEmpty(_defaultText))
+ {
+ _textBox.Text = _defaultText;
+ SetSelectedDateTime();
+ }
+ }
+ else
+ {
+ _textBox.Text = DateTimeToString(SelectedDateTime.Value);
+ }
+
+ if (_originalSelectedDateTime == null)
+ {
+ _originalSelectedDateTime = DateTime.Now;
+ }
+ SetCurrentValue(DisplayDateTimeProperty, _originalSelectedDateTime);
+ }
+
+ public virtual bool VerifyData()
+ {
+ OperationResult result;
+
+ if (VerifyFunc != null)
+ {
+ result = VerifyFunc.Invoke(Text);
+ }
+ else
+ {
+ if (!string.IsNullOrEmpty(Text))
+ {
+ result = OperationResult.Success();
+ }
+ else if (InfoElement.GetNecessary(this))
+ {
+ result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
+ }
+ else
+ {
+ result = OperationResult.Success();
+ }
+ }
+
+ IsError = !result.Data;
+ ErrorStr = result.Message;
+ return result.Data;
+ }
+
+ public override string ToString() => SelectedDateTime?.ToString(DateTimeFormat) ?? string.Empty;
+
+ #endregion
+
+ #region Protected Methods
+
+ protected virtual void OnPickerClosed(RoutedEventArgs e)
+ {
+ var handler = PickerClosed;
+ handler?.Invoke(this, e);
+ }
+
+ protected virtual void OnPickerOpened(RoutedEventArgs e)
+ {
+ var handler = PickerOpened;
+ handler?.Invoke(this, e);
+ }
+
+ #endregion Protected Methods
+
+ #region Private Methods
+
+ private void CheckNull()
+ {
+ if (_dropDownButton == null || _popUp == null || _textBox == null)
+ throw new Exception();
+ }
+
+ private void InitCalendarWithClock()
+ {
+ _calendarWithClock = new CalendarWithClock
+ {
+ ShowConfirmButton = true
+ };
+ _calendarWithClock.SelectedDateTimeChanged += CalendarWithClock_SelectedDateTimeChanged;
+ _calendarWithClock.Confirmed += CalendarWithClock_Confirmed;
+ }
+
+ private void CalendarWithClock_Confirmed() => TogglePopUp();
+
+ private void CalendarWithClock_SelectedDateTimeChanged(object sender, FunctionEventArgs e) => SelectedDateTime = e.Info;
+
+ private void TextBox_LostFocus(object sender, RoutedEventArgs e)
+ {
+ SetSelectedDateTime();
+ }
+
+ private void SetIsHandlerSuspended(DependencyProperty property, bool value)
+ {
+ if (value)
+ {
+ if (_isHandlerSuspended == null)
+ {
+ _isHandlerSuspended = new Dictionary(2);
+ }
+
+ _isHandlerSuspended[property] = true;
+ }
+ else
+ {
+ _isHandlerSuspended?.Remove(property);
+ }
+ }
+
+ private void SetValueNoCallback(DependencyProperty property, object value)
+ {
+ SetIsHandlerSuspended(property, true);
+ try
+ {
+ SetCurrentValue(property, value);
+ }
+ finally
+ {
+ SetIsHandlerSuspended(property, false);
+ }
+ }
+
+ private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ SetValueNoCallback(TextProperty, _textBox.Text);
+ VerifyData();
+ }
+
+ private bool ProcessDateTimePickerKey(KeyEventArgs e)
+ {
+ switch (e.Key)
+ {
+ case Key.System:
+ {
+ switch (e.SystemKey)
+ {
+ case Key.Down:
+ {
+ if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
+ {
+ TogglePopUp();
+ return true;
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case Key.Enter:
+ {
+ SetSelectedDateTime();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void TextBox_KeyDown(object sender, KeyEventArgs e)
+ {
+ e.Handled = ProcessDateTimePickerKey(e) || e.Handled;
+ }
+
+ private void DropDownButton_MouseLeave(object sender, MouseEventArgs e)
+ {
+ _disablePopupReopen = false;
+ }
+
+ private bool IsHandlerSuspended(DependencyProperty property)
+ {
+ return _isHandlerSuspended != null && _isHandlerSuspended.ContainsKey(property);
+ }
+
+ private void PopUp_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ if (sender is Popup popup && !popup.StaysOpen)
+ {
+ if (_dropDownButton?.InputHitTest(e.GetPosition(_dropDownButton)) != null)
+ {
+ _disablePopupReopen = true;
+ }
+ }
+ }
+
+ private void PopUp_Opened(object sender, EventArgs e)
+ {
+ if (!IsDropDownOpen)
+ {
+ SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
+ }
+
+ _calendarWithClock?.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
+
+ OnPickerOpened(new RoutedEventArgs());
+ }
+
+ private void PopUp_Closed(object sender, EventArgs e)
+ {
+ if (IsDropDownOpen)
+ {
+ SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
+ }
+
+ if (_calendarWithClock.IsKeyboardFocusWithin)
+ {
+ MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
+ }
+
+ OnPickerClosed(new RoutedEventArgs());
+ }
+
+ private void DropDownButton_Click(object sender, RoutedEventArgs e) => TogglePopUp();
+
+ private void TogglePopUp()
+ {
+ if (IsDropDownOpen)
+ {
+ SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
+ }
+ else
+ {
+ if (_disablePopupReopen)
+ {
+ _disablePopupReopen = false;
+ }
+ else
+ {
+ SetSelectedDateTime();
+ SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
+ }
+ }
+ }
+
+ private void SafeSetText(string s)
+ {
+ if (string.Compare(Text, s, StringComparison.Ordinal) != 0)
+ {
+ SetCurrentValue(TextProperty, s);
+ }
+ }
+
+ private DateTime? ParseText(string text)
+ {
+ try
+ {
+ return DateTime.Parse(text);
+ }
+ catch
+ {
+ // ignored
+ }
+
+ return null;
+ }
+
+ private DateTime? SetTextBoxValue(string s)
+ {
+ if (string.IsNullOrEmpty(s))
+ {
+ SafeSetText(s);
+ return SelectedDateTime;
+ }
+
+ var d = ParseText(s);
+
+ if (d != null)
+ {
+ SafeSetText(DateTimeToString((DateTime)d));
+ return d;
+ }
+
+ if (SelectedDateTime != null)
+ {
+ var newtext = DateTimeToString(SelectedDateTime.Value);
+ SafeSetText(newtext);
+ return SelectedDateTime;
+ }
+ SafeSetText(DateTimeToString(DisplayDateTime));
+ return DisplayDateTime;
+ }
+
+ private void SetSelectedDateTime()
+ {
+ if (_textBox != null)
+ {
+ if (!string.IsNullOrEmpty(_textBox.Text))
+ {
+ var s = _textBox.Text;
+
+ if (SelectedDateTime != null)
+ {
+ var selectedTime = DateTimeToString(SelectedDateTime.Value);
+
+ if (string.Compare(selectedTime, s, StringComparison.Ordinal) == 0)
+ {
+ return;
+ }
+ }
+
+ var d = SetTextBoxValue(s);
+ if (!SelectedDateTime.Equals(d))
+ {
+ SetCurrentValue(SelectedDateTimeProperty, d);
+ SetCurrentValue(DisplayDateTimeProperty, d);
+ }
+ }
+ else
+ {
+ if (SelectedDateTime.HasValue)
+ {
+ SetCurrentValue(SelectedDateTimeProperty, null);
+ }
+ }
+ }
+ else
+ {
+ var d = SetTextBoxValue(_defaultText);
+ if (!SelectedDateTime.Equals(d))
+ {
+ SetCurrentValue(SelectedDateTimeProperty, d);
+ }
+ }
+ }
+
+ private string DateTimeToString(DateTime d) => d.ToString(DateTimeFormat);
+
+ private static void OnGotFocus(object sender, RoutedEventArgs e)
+ {
+ var picker = (DateTimePicker)sender;
+ if (!e.Handled && picker._textBox != null)
+ {
+ if (Equals(e.OriginalSource, picker))
+ {
+ picker._textBox.Focus();
+ e.Handled = true;
+ }
+ else if (Equals(e.OriginalSource, picker._textBox))
+ {
+ picker._textBox.SelectAll();
+ e.Handled = true;
+ }
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Controls/Input/TimePicker.cs b/HandyControl/Controls/Input/TimePicker.cs
index d9c2648b..25d005de 100644
--- a/HandyControl/Controls/Input/TimePicker.cs
+++ b/HandyControl/Controls/Input/TimePicker.cs
@@ -18,28 +18,36 @@ namespace HandyControl.Controls
[TemplatePart(Name = ElementTextBox, Type = typeof(WatermarkTextBox))]
[TemplatePart(Name = ElementButton, Type = typeof(Button))]
[TemplatePart(Name = ElementPopup, Type = typeof(Popup))]
- [TemplatePart(Name = ElementClock, Type = typeof(Clock))]
public class TimePicker : Control, IDataInput
{
#region Constants
private const string ElementRoot = "PART_Root";
+
private const string ElementTextBox = "PART_TextBox";
+
private const string ElementButton = "PART_Button";
+
private const string ElementPopup = "PART_Popup";
- private const string ElementClock = "PART_Clock";
#endregion Constants
#region Data
private Clock _clock;
+
private string _defaultText;
+
private ButtonBase _dropDownButton;
+
private Popup _popUp;
+
private bool _disablePopupReopen;
+
private WatermarkTextBox _textBox;
+
private IDictionary _isHandlerSuspended;
+
private DateTime? _originalSelectedTime;
#endregion Data
@@ -71,10 +79,12 @@ namespace HandyControl.Controls
public TimePicker()
{
+ InitClock();
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
{
ClearValue(SelectedTimeProperty);
ClearValue(TextProperty);
+ _textBox.Text = string.Empty;
}));
}
@@ -142,7 +152,7 @@ namespace HandyControl.Controls
"IsDropDownOpen",
typeof(bool),
typeof(TimePicker),
- new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsDropDownOpenChanged, OnCoerceIsDropDownOpen));
+ new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsDropDownOpenChanged, OnCoerceIsDropDownOpen));
private static object OnCoerceIsDropDownOpen(DependencyObject d, object baseValue) => d is TimePicker dp && !dp.IsEnabled ? false : baseValue;
@@ -334,7 +344,7 @@ namespace HandyControl.Controls
if (DesignerProperties.GetIsInDesignMode(this)) return;
if (_popUp != null)
{
- _popUp.RemoveHandler(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(PopUp_PreviewMouseLeftButtonDown));
+ _popUp.PreviewMouseLeftButtonDown -= PopUp_PreviewMouseLeftButtonDown;
_popUp.Opened -= PopUp_Opened;
_popUp.Closed -= PopUp_Closed;
_popUp.Child = null;
@@ -343,36 +353,25 @@ namespace HandyControl.Controls
if (_dropDownButton != null)
{
_dropDownButton.Click -= DropDownButton_Click;
- _dropDownButton.RemoveHandler(MouseLeaveEvent, new MouseEventHandler(DropDownButton_MouseLeave));
+ _dropDownButton.MouseLeave -= DropDownButton_MouseLeave;
}
if (_textBox != null)
{
- _textBox.RemoveHandler(KeyDownEvent, new KeyEventHandler(TextBox_KeyDown));
- _textBox.RemoveHandler(TextBoxBase.TextChangedEvent, new TextChangedEventHandler(TextBox_TextChanged));
- _textBox.RemoveHandler(LostFocusEvent, new RoutedEventHandler(TextBox_LostFocus));
- }
-
- if (_clock != null)
- {
- _clock.RemoveHandler(Clock.SelectedTimeChangedEvent, new EventHandler>(Clock_SelectedTimeChangedEvent));
- _clock.Confirmed -= Clock_Confirmed;
+ _textBox.KeyDown -= TextBox_KeyDown;
+ _textBox.TextChanged -= TextBox_TextChanged;
+ _textBox.LostFocus -= TextBox_LostFocus;
}
base.OnApplyTemplate();
- _clock = GetTemplateChild(ElementClock) as Clock;
_popUp = GetTemplateChild(ElementPopup) as Popup;
_dropDownButton = GetTemplateChild(ElementButton) as Button;
_textBox = GetTemplateChild(ElementTextBox) as WatermarkTextBox;
CheckNull();
- _clock.ApplyTemplate();
- _clock.AddHandler(Clock.SelectedTimeChangedEvent, new EventHandler>(Clock_SelectedTimeChangedEvent));
- _clock.Confirmed += Clock_Confirmed;
-
- _popUp.AddHandler(PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(PopUp_PreviewMouseLeftButtonDown));
+ _popUp.PreviewMouseLeftButtonDown += PopUp_PreviewMouseLeftButtonDown;
_popUp.Opened += PopUp_Opened;
_popUp.Closed += PopUp_Closed;
_popUp.Child = _clock;
@@ -383,14 +382,14 @@ namespace HandyControl.Controls
}
_dropDownButton.Click += DropDownButton_Click;
- _dropDownButton.AddHandler(MouseLeaveEvent, new MouseEventHandler(DropDownButton_MouseLeave), true);
+ _dropDownButton.MouseLeave += DropDownButton_MouseLeave;
if (SelectedTime == null)
{
_textBox.Text = DateTime.Now.ToString(TimeFormat);
}
- _textBox.AddHandler(KeyDownEvent, new KeyEventHandler(TextBox_KeyDown), true);
- _textBox.AddHandler(TextBoxBase.TextChangedEvent, new TextChangedEventHandler(TextBox_TextChanged), true);
- _textBox.AddHandler(LostFocusEvent, new RoutedEventHandler(TextBox_LostFocus), true);
+ _textBox.KeyDown += TextBox_KeyDown;
+ _textBox.TextChanged += TextBox_TextChanged;
+ _textBox.LostFocus += TextBox_LostFocus;
if (SelectedTime == null)
{
@@ -436,10 +435,20 @@ namespace HandyControl.Controls
private void CheckNull()
{
- if (_clock == null || _dropDownButton == null || _popUp == null || _textBox == null)
+ if (_dropDownButton == null || _popUp == null || _textBox == null)
throw new Exception();
}
+ private void InitClock()
+ {
+ _clock = new Clock
+ {
+ ShowConfirmButton = true
+ };
+ _clock.SelectedTimeChanged += Clock_SelectedTimeChanged;
+ _clock.Confirmed += Clock_Confirmed;
+ }
+
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
SetSelectedTime();
@@ -540,7 +549,7 @@ namespace HandyControl.Controls
}
}
- private void Clock_SelectedTimeChangedEvent(object sender, FunctionEventArgs e) => SelectedTime = e.Info;
+ private void Clock_SelectedTimeChanged(object sender, FunctionEventArgs e) => SelectedTime = e.Info;
private void Clock_Confirmed() => TogglePopUp();
diff --git a/HandyControl/Controls/Time/CalendarWithClock.cs b/HandyControl/Controls/Time/CalendarWithClock.cs
new file mode 100644
index 00000000..e8e2c353
--- /dev/null
+++ b/HandyControl/Controls/Time/CalendarWithClock.cs
@@ -0,0 +1,260 @@
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using HandyControl.Data;
+
+namespace HandyControl.Controls
+{
+ [TemplatePart(Name = ElementButtonConfirm, Type = typeof(Button))]
+ [TemplatePart(Name = ElementClockPresenter, Type = typeof(ContentPresenter))]
+ [TemplatePart(Name = ElementCalendarPresenter, Type = typeof(ContentPresenter))]
+ public class CalendarWithClock : Control
+ {
+ #region Constants
+
+ private const string ElementButtonConfirm = "PART_ButtonConfirm";
+
+ private const string ElementClockPresenter = "PART_ClockPresenter";
+
+ private const string ElementCalendarPresenter = "PART_CalendarPresenter";
+
+ #endregion Constants
+
+ #region Data
+
+ private ContentPresenter _clockPresenter;
+
+ private ContentPresenter _calendarPresenter;
+
+ private Clock _clock;
+
+ private Calendar _calendar;
+
+ private Button _buttonConfirm;
+
+ private bool _isLoaded;
+
+ private IDictionary _isHandlerSuspended;
+
+ #endregion Data
+
+ #region Public Events
+
+ public static readonly RoutedEvent SelectedDateTimeChangedEvent =
+ EventManager.RegisterRoutedEvent("SelectedDateTimeChanged", RoutingStrategy.Direct,
+ typeof(EventHandler>), typeof(CalendarWithClock));
+
+ public event EventHandler> SelectedDateTimeChanged
+ {
+ add => AddHandler(SelectedDateTimeChangedEvent, value);
+ remove => RemoveHandler(SelectedDateTimeChangedEvent, value);
+ }
+
+ public event EventHandler> DisplayDateTimeChanged;
+
+ public event Action Confirmed;
+
+ #endregion Public Events
+
+ public CalendarWithClock()
+ {
+ InitCalendarAndClock();
+ Loaded += (s, e) =>
+ {
+ if (_isLoaded) return;
+ _isLoaded = true;
+ DisplayDateTime = SelectedDateTime ?? DateTime.Now;
+ };
+ }
+
+ #region Public Properties
+
+ public static readonly DependencyProperty DateTimeFormatProperty = DependencyProperty.Register(
+ "DateTimeFormat", typeof(string), typeof(CalendarWithClock), new PropertyMetadata("yyyy-MM-dd HH:mm:ss"));
+
+ public string DateTimeFormat
+ {
+ get => (string)GetValue(DateTimeFormatProperty);
+ set => SetValue(DateTimeFormatProperty, value);
+ }
+
+ public static readonly DependencyProperty ShowConfirmButtonProperty = DependencyProperty.Register(
+ "ShowConfirmButton", typeof(bool), typeof(CalendarWithClock), new PropertyMetadata(ValueBoxes.FalseBox));
+
+ public bool ShowConfirmButton
+ {
+ get => (bool)GetValue(ShowConfirmButtonProperty);
+ set => SetValue(ShowConfirmButtonProperty, value);
+ }
+
+ public static readonly DependencyProperty SelectedDateTimeProperty = DependencyProperty.Register(
+ "SelectedDateTime", typeof(DateTime?), typeof(CalendarWithClock), new PropertyMetadata(default(DateTime?), OnSelectedDateTimeChanged));
+
+ private static void OnSelectedDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctl = (CalendarWithClock)d;
+ var v = (DateTime?)e.NewValue;
+ ctl.OnSelectedDateTimeChanged(new FunctionEventArgs(SelectedDateTimeChangedEvent, ctl)
+ {
+ Info = v
+ });
+ }
+
+ public DateTime? SelectedDateTime
+ {
+ get => (DateTime?)GetValue(SelectedDateTimeProperty);
+ set => SetValue(SelectedDateTimeProperty, value);
+ }
+
+ public static readonly DependencyProperty DisplayDateTimeProperty = DependencyProperty.Register(
+ "DisplayDateTime", typeof(DateTime), typeof(CalendarWithClock), new FrameworkPropertyMetadata(DateTime.MinValue, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDisplayDateTimeChanged));
+
+ private static void OnDisplayDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var ctl = (CalendarWithClock)d;
+ if (ctl.IsHandlerSuspended(DisplayDateTimeProperty)) return;
+ var v = (DateTime)e.NewValue;
+ ctl._clock.SelectedTime = v;
+ ctl._calendar.SelectedDate = v;
+ ctl.OnDisplayDateTimeChanged(new FunctionEventArgs(v));
+ }
+
+ public DateTime DisplayDateTime
+ {
+ get => (DateTime)GetValue(DisplayDateTimeProperty);
+ set => SetValue(DisplayDateTimeProperty, value);
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ public override void OnApplyTemplate()
+ {
+ if (_buttonConfirm != null)
+ {
+ _buttonConfirm.Click -= ButtonConfirm_OnClick;
+ }
+
+ base.OnApplyTemplate();
+
+ _buttonConfirm = GetTemplateChild(ElementButtonConfirm) as Button;
+ _clockPresenter = GetTemplateChild(ElementClockPresenter) as ContentPresenter;
+ _calendarPresenter = GetTemplateChild(ElementCalendarPresenter) as ContentPresenter;
+
+ CheckNull();
+
+ _clockPresenter.Content = _clock;
+ _calendarPresenter.Content = _calendar;
+
+ _buttonConfirm.Click += ButtonConfirm_OnClick;
+ }
+
+ #endregion
+
+ #region Protected Methods
+
+ protected virtual void OnSelectedDateTimeChanged(FunctionEventArgs e) => RaiseEvent(e);
+
+ protected virtual void OnDisplayDateTimeChanged(FunctionEventArgs e)
+ {
+ var handler = DisplayDateTimeChanged;
+ handler?.Invoke(this, e);
+ }
+
+ #endregion Protected Methods
+
+ #region Private Methods
+
+ private void SetIsHandlerSuspended(DependencyProperty property, bool value)
+ {
+ if (value)
+ {
+ if (_isHandlerSuspended == null)
+ {
+ _isHandlerSuspended = new Dictionary(2);
+ }
+
+ _isHandlerSuspended[property] = true;
+ }
+ else
+ {
+ _isHandlerSuspended?.Remove(property);
+ }
+ }
+
+ private void SetValueNoCallback(DependencyProperty property, object value)
+ {
+ SetIsHandlerSuspended(property, true);
+ try
+ {
+ SetCurrentValue(property, value);
+ }
+ finally
+ {
+ SetIsHandlerSuspended(property, false);
+ }
+ }
+
+ private bool IsHandlerSuspended(DependencyProperty property)
+ {
+ return _isHandlerSuspended != null && _isHandlerSuspended.ContainsKey(property);
+ }
+
+ private void CheckNull()
+ {
+ if (_buttonConfirm == null || _clockPresenter == null || _calendarPresenter == null) throw new Exception();
+ }
+
+ private void ButtonConfirm_OnClick(object sender, RoutedEventArgs e)
+ {
+ SelectedDateTime = DisplayDateTime;
+ Confirmed?.Invoke();
+ }
+
+ private void InitCalendarAndClock()
+ {
+ _clock = new Clock
+ {
+ BorderThickness = new Thickness(),
+ Background = Brushes.Transparent
+ };
+ TitleElement.SetBackground(_clock, Brushes.Transparent);
+ _clock.DisplayTimeChanged += Clock_DisplayTimeChanged;
+
+ _calendar = new Calendar
+ {
+ BorderThickness = new Thickness(),
+ Background = Brushes.Transparent,
+ Focusable = false
+ };
+ TitleElement.SetBackground(_calendar, Brushes.Transparent);
+ _calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
+ }
+
+ private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
+ {
+ Mouse.Capture(null);
+ UpdateDisplayTime();
+ }
+
+ private void Clock_DisplayTimeChanged(object sender, FunctionEventArgs e) => UpdateDisplayTime();
+
+ private void UpdateDisplayTime()
+ {
+ if (_calendar.SelectedDate != null)
+ {
+ var date = _calendar.SelectedDate.Value;
+ var time = _clock.DisplayTime;
+
+ var result = new DateTime(date.Year, date.Month, date.Day, time.Hour, time.Minute, time.Second);
+ SetValueNoCallback(DisplayDateTimeProperty, result);
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Controls/Clock/Clock.cs b/HandyControl/Controls/Time/Clock/Clock.cs
similarity index 85%
rename from HandyControl/Controls/Clock/Clock.cs
rename to HandyControl/Controls/Time/Clock/Clock.cs
index 647c5d79..ca43b8da 100644
--- a/HandyControl/Controls/Clock/Clock.cs
+++ b/HandyControl/Controls/Time/Clock/Clock.cs
@@ -9,7 +9,6 @@ using System.Windows.Media;
using HandyControl.Data;
using HandyControl.Tools;
-// ReSharper disable once CheckNamespace
namespace HandyControl.Controls
{
[TemplatePart(Name = ElementButtonAm, Type = typeof(RadioButton))]
@@ -61,8 +60,6 @@ namespace HandyControl.Controls
private int _secValue;
- private bool _isLoaded;
-
private bool _appliedTemplate;
#endregion Data
@@ -79,22 +76,12 @@ namespace HandyControl.Controls
remove => RemoveHandler(SelectedTimeChangedEvent, value);
}
- public event EventHandler> DisplayTimeChanged;
+ public event EventHandler> DisplayTimeChanged;
public event Action Confirmed;
#endregion Public Events
- public Clock()
- {
- Loaded += (s, e) =>
- {
- if (_isLoaded) return;
- _isLoaded = true;
- DisplayTime = DateTime.Now;
- };
- }
-
#region Public Properties
public static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register(
@@ -104,6 +91,7 @@ namespace HandyControl.Controls
{
var ctl = (Clock)d;
var v = (DateTime?)e.NewValue;
+ ctl.DisplayTime = v ?? DateTime.Now;
ctl.OnSelectedTimeChanged(new FunctionEventArgs(SelectedTimeChangedEvent, ctl)
{
Info = v
@@ -135,14 +123,14 @@ namespace HandyControl.Controls
}
public static readonly DependencyProperty DisplayTimeProperty = DependencyProperty.Register(
- "DisplayTime", typeof(DateTime), typeof(Clock), new FrameworkPropertyMetadata(DateTime.MinValue, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDisplayTimeChanged));
+ "DisplayTime", typeof(DateTime), typeof(Clock), new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDisplayTimeChanged));
private static void OnDisplayTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (Clock) d;
var v = (DateTime) e.NewValue;
ctl.Update(v);
- ctl.OnDisplayTimeChanged(new FunctionEventArgs(v));
+ ctl.OnDisplayTimeChanged(new FunctionEventArgs(v));
}
public DateTime DisplayTime
@@ -187,16 +175,31 @@ namespace HandyControl.Controls
public override void OnApplyTemplate()
{
_appliedTemplate = false;
- _buttonAm?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonAm_OnClick));
- _buttonPm?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPm_OnClick));
- _buttonConfirm?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonConfirm_OnClick));
- _borderTitle?.RemoveHandler(MouseWheelEvent, new MouseWheelEventHandler(BorderTitle_OnMouseWheel));
+ if (_buttonAm != null)
+ {
+ _buttonAm.Click -= ButtonAm_OnClick;
+ }
+
+ if (_buttonPm != null)
+ {
+ _buttonPm.Click -= ButtonPm_OnClick;
+ }
+
+ if (_buttonConfirm != null)
+ {
+ _buttonConfirm.Click -= ButtonConfirm_OnClick;
+ }
+
+ if (_borderTitle != null)
+ {
+ _borderTitle.MouseWheel -= BorderTitle_OnMouseWheel;
+ }
if (_canvas != null)
{
- _canvas.RemoveHandler(MouseWheelEvent, new MouseWheelEventHandler(MyCanvas_OnMouseWheel));
- _canvas.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(MyCanvas_OnClick));
- _canvas.RemoveHandler(MouseMoveEvent, new MouseEventHandler(MyCanvas_OnMouseMove));
+ _canvas.MouseWheel -= Canvas_OnMouseWheel;
+ _canvas.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Canvas_OnClick));
+ _canvas.MouseMove -= Canvas_OnMouseMove;
}
base.OnApplyTemplate();
@@ -212,14 +215,14 @@ namespace HandyControl.Controls
CheckNull();
- _buttonAm.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonAm_OnClick));
- _buttonPm.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPm_OnClick));
- _buttonConfirm.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonConfirm_OnClick));
- _borderTitle.AddHandler(MouseWheelEvent, new MouseWheelEventHandler(BorderTitle_OnMouseWheel));
+ _buttonAm.Click += ButtonAm_OnClick;
+ _buttonPm.Click += ButtonPm_OnClick;
+ _buttonConfirm.Click += ButtonConfirm_OnClick;
+ _borderTitle.MouseWheel += BorderTitle_OnMouseWheel;
- _canvas.AddHandler(MouseWheelEvent, new MouseWheelEventHandler(MyCanvas_OnMouseWheel));
- _canvas.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(MyCanvas_OnClick));
- _canvas.AddHandler(MouseMoveEvent, new MouseEventHandler(MyCanvas_OnMouseMove));
+ _canvas.MouseWheel += Canvas_OnMouseWheel;
+ _canvas.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Canvas_OnClick));
+ _canvas.MouseMove += Canvas_OnMouseMove;
_rotateTransformClock = new RotateTransform();
_borderClock.RenderTransform = _rotateTransformClock;
@@ -239,9 +242,14 @@ namespace HandyControl.Controls
}
_appliedTemplate = true;
- if (_isLoaded)
+ if (SelectedTime.HasValue)
{
- Update(SelectedTime ?? DisplayTime);
+ Update(SelectedTime.Value);
+ }
+ else
+ {
+ DisplayTime = DateTime.Now;
+ Update(DisplayTime);
}
}
@@ -251,7 +259,7 @@ namespace HandyControl.Controls
protected virtual void OnSelectedTimeChanged(FunctionEventArgs e) => RaiseEvent(e);
- protected virtual void OnDisplayTimeChanged(FunctionEventArgs e)
+ protected virtual void OnDisplayTimeChanged(FunctionEventArgs e)
{
var handler = DisplayTimeChanged;
handler?.Invoke(this, e);
@@ -284,7 +292,7 @@ namespace HandyControl.Controls
e.Handled = true;
}
- private void MyCanvas_OnMouseWheel(object sender, MouseWheelEventArgs e)
+ private void Canvas_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
var value = (int)_rotateTransformClock.Angle;
if (e.Delta < 0)
@@ -305,7 +313,7 @@ namespace HandyControl.Controls
e.Handled = true;
}
- private void MyCanvas_OnClick(object sender, RoutedEventArgs e)
+ private void Canvas_OnClick(object sender, RoutedEventArgs e)
{
_currentButton = e.OriginalSource as ClockRadioButton;
if (_currentButton != null)
@@ -314,7 +322,7 @@ namespace HandyControl.Controls
}
}
- private void MyCanvas_OnMouseMove(object sender, MouseEventArgs e)
+ private void Canvas_OnMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
@@ -359,7 +367,7 @@ namespace HandyControl.Controls
/// 更新
///
///
- private void Update(DateTime time)
+ internal void Update(DateTime time)
{
if (!_appliedTemplate) return;
var h = time.Hour;
diff --git a/HandyControl/Controls/Clock/ClockRadioButton.cs b/HandyControl/Controls/Time/Clock/ClockRadioButton.cs
similarity index 100%
rename from HandyControl/Controls/Clock/ClockRadioButton.cs
rename to HandyControl/Controls/Time/Clock/ClockRadioButton.cs
diff --git a/HandyControl/Controls/TimeBar/SpeTextBlock.cs b/HandyControl/Controls/Time/TimeBar/SpeTextBlock.cs
similarity index 100%
rename from HandyControl/Controls/TimeBar/SpeTextBlock.cs
rename to HandyControl/Controls/Time/TimeBar/SpeTextBlock.cs
diff --git a/HandyControl/Controls/TimeBar/TimeBar.cs b/HandyControl/Controls/Time/TimeBar/TimeBar.cs
similarity index 100%
rename from HandyControl/Controls/TimeBar/TimeBar.cs
rename to HandyControl/Controls/Time/TimeBar/TimeBar.cs
diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj
index 11a33412..60886f13 100644
--- a/HandyControl/HandyControl.csproj
+++ b/HandyControl/HandyControl.csproj
@@ -43,17 +43,20 @@
+
-
-
+
+
+
+
@@ -121,9 +124,9 @@
-
+
-
+
@@ -260,6 +263,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -356,6 +363,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -392,6 +403,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/HandyControl/Themes/Styles/Base/DateTimePickerBaseStyle.xaml b/HandyControl/Themes/Styles/Base/DateTimePickerBaseStyle.xaml
new file mode 100644
index 00000000..8da97a44
--- /dev/null
+++ b/HandyControl/Themes/Styles/Base/DateTimePickerBaseStyle.xaml
@@ -0,0 +1,338 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HandyControl/Themes/Styles/Base/TimePickerBaseStyle.xaml b/HandyControl/Themes/Styles/Base/TimePickerBaseStyle.xaml
index 9c468abe..02aefe3e 100644
--- a/HandyControl/Themes/Styles/Base/TimePickerBaseStyle.xaml
+++ b/HandyControl/Themes/Styles/Base/TimePickerBaseStyle.xaml
@@ -29,9 +29,7 @@
-
-
-
+
@@ -82,9 +80,7 @@
-
-
-
+
@@ -133,9 +129,7 @@
-
-
-
+
@@ -208,9 +202,7 @@
-
-
-
+
@@ -286,9 +278,7 @@
-
-
-
+
diff --git a/HandyControl/Themes/Styles/Calendar.xaml b/HandyControl/Themes/Styles/Calendar.xaml
index bf3529d4..f8af46b9 100644
--- a/HandyControl/Themes/Styles/Calendar.xaml
+++ b/HandyControl/Themes/Styles/Calendar.xaml
@@ -63,6 +63,7 @@
+
+
+
\ No newline at end of file
diff --git a/HandyControl/Themes/Styles/Clock.xaml b/HandyControl/Themes/Styles/Clock.xaml
index ff03faa5..a54dd92c 100644
--- a/HandyControl/Themes/Styles/Clock.xaml
+++ b/HandyControl/Themes/Styles/Clock.xaml
@@ -61,22 +61,23 @@
-
+
+
-
+
-
-
+
+
diff --git a/HandyControl/Themes/Styles/DateTimePicker.xaml b/HandyControl/Themes/Styles/DateTimePicker.xaml
new file mode 100644
index 00000000..7c3fc209
--- /dev/null
+++ b/HandyControl/Themes/Styles/DateTimePicker.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/HandyControl/Themes/Styles/Style.xaml b/HandyControl/Themes/Styles/Style.xaml
index 4b1ae3c8..6c487bf3 100644
--- a/HandyControl/Themes/Styles/Style.xaml
+++ b/HandyControl/Themes/Styles/Style.xaml
@@ -38,6 +38,8 @@
+
+
\ No newline at end of file
diff --git a/HandyControlDemo/Data/MessageToken.cs b/HandyControlDemo/Data/MessageToken.cs
index f2ecae60..d1ca4a80 100644
--- a/HandyControlDemo/Data/MessageToken.cs
+++ b/HandyControlDemo/Data/MessageToken.cs
@@ -46,6 +46,10 @@
public static readonly string DatePickerDemoCtl = nameof(DatePickerDemoCtl);
+ public static readonly string DateTimePickerDemoCtl = nameof(DateTimePickerDemoCtl);
+
+ public static readonly string CalendarWithClockDemoCtl = nameof(CalendarWithClockDemoCtl);
+
public static readonly string ButtonDemoCtl = nameof(ButtonDemoCtl);
public static readonly string ToggleButtonDemoCtl = nameof(ToggleButtonDemoCtl);
diff --git a/HandyControlDemo/Data/MessageToken.tt b/HandyControlDemo/Data/MessageToken.tt
index 7fca17ce..de08920d 100644
--- a/HandyControlDemo/Data/MessageToken.tt
+++ b/HandyControlDemo/Data/MessageToken.tt
@@ -25,7 +25,9 @@ var controlList = new List
"TextBoxDemoCtl",
"ComboBoxDemoCtl",
"PasswordBoxDemoCtl",
- "DatePickerDemoCtl"
+ "DatePickerDemoCtl",
+ "DateTimePickerDemoCtl",
+ "CalendarWithClockDemoCtl"
};
var styleList = new List
{
diff --git a/HandyControlDemo/HandyControlDemo.csproj b/HandyControlDemo/HandyControlDemo.csproj
index 86388ef9..7cc7a554 100644
--- a/HandyControlDemo/HandyControlDemo.csproj
+++ b/HandyControlDemo/HandyControlDemo.csproj
@@ -99,6 +99,9 @@
AnimationPathDemoCtl.xaml
+
+ CalendarWithClockDemoCtl.xaml
+
CarouselDemoCtl.xaml
@@ -123,6 +126,9 @@
DatePickerDemoCtl.xaml
+
+ DateTimePickerDemoCtl.xaml
+
GrowlDemoCtl.xaml
@@ -319,6 +325,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -351,6 +361,10 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/HandyControlDemo/Properties/Langs/Lang.Designer.cs b/HandyControlDemo/Properties/Langs/Lang.Designer.cs
index 72f792c7..f1b96921 100644
--- a/HandyControlDemo/Properties/Langs/Lang.Designer.cs
+++ b/HandyControlDemo/Properties/Langs/Lang.Designer.cs
@@ -47,7 +47,7 @@ namespace HandyControlDemo.Properties.Langs {
}
///
- /// 使用此强类型资源类,为所有资源查找
+ /// 重写当前线程的 CurrentUICulture 属性
/// 重写当前线程的 CurrentUICulture 属性。
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
@@ -150,6 +150,15 @@ namespace HandyControlDemo.Properties.Langs {
}
}
+ ///
+ /// 查找类似 带时钟的日历 的本地化字符串。
+ ///
+ public static string CalendarWithClock {
+ get {
+ return ResourceManager.GetString("CalendarWithClock", resourceCulture);
+ }
+ }
+
///
/// 查找类似 轮播 的本地化字符串。
///
@@ -312,6 +321,15 @@ namespace HandyControlDemo.Properties.Langs {
}
}
+ ///
+ /// 查找类似 日期时间选择器 的本地化字符串。
+ ///
+ public static string DateTimePicker {
+ get {
+ return ResourceManager.GetString("DateTimePicker", resourceCulture);
+ }
+ }
+
///
/// 查找类似 默认 的本地化字符串。
///
diff --git a/HandyControlDemo/Properties/Langs/Lang.en.resx b/HandyControlDemo/Properties/Langs/Lang.en.resx
index 7a38c4e6..454724c4 100644
--- a/HandyControlDemo/Properties/Langs/Lang.en.resx
+++ b/HandyControlDemo/Properties/Langs/Lang.en.resx
@@ -399,4 +399,10 @@
Step
+
+ CalendarWithClock
+
+
+ DateTimePicker
+
\ No newline at end of file
diff --git a/HandyControlDemo/Properties/Langs/Lang.resx b/HandyControlDemo/Properties/Langs/Lang.resx
index bb77a022..e4f29540 100644
--- a/HandyControlDemo/Properties/Langs/Lang.resx
+++ b/HandyControlDemo/Properties/Langs/Lang.resx
@@ -379,4 +379,10 @@
步骤
+
+ 带时钟的日历
+
+
+ 日期时间选择器
+
\ No newline at end of file
diff --git a/HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml
new file mode 100644
index 00000000..69eb771d
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml.cs b/HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml.cs
new file mode 100644
index 00000000..ec65eb73
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/CalendarWithClockDemoCtl.xaml.cs
@@ -0,0 +1,10 @@
+namespace HandyControlDemo.UserControl
+{
+ public partial class CalendarWithClockDemoCtl
+ {
+ public CalendarWithClockDemoCtl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/HandyControlDemo/UserControl/Controls/DatePickerDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/DatePickerDemoCtl.xaml
index 840081e3..39e23fed 100644
--- a/HandyControlDemo/UserControl/Controls/DatePickerDemoCtl.xaml
+++ b/HandyControlDemo/UserControl/Controls/DatePickerDemoCtl.xaml
@@ -4,7 +4,7 @@
xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs"
- Background="White">
+ Background="{DynamicResource RegionBrush}">
diff --git a/HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml
new file mode 100644
index 00000000..d47ea7a3
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml.cs b/HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml.cs
new file mode 100644
index 00000000..2ddac486
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/DateTimePickerDemoCtl.xaml.cs
@@ -0,0 +1,10 @@
+namespace HandyControlDemo.UserControl
+{
+ public partial class DateTimePickerDemoCtl
+ {
+ public DateTimePickerDemoCtl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/HandyControlDemo/UserControl/Controls/TimePickerDemoCtl.xaml.cs b/HandyControlDemo/UserControl/Controls/TimePickerDemoCtl.xaml.cs
index 3f78a428..235af412 100644
--- a/HandyControlDemo/UserControl/Controls/TimePickerDemoCtl.xaml.cs
+++ b/HandyControlDemo/UserControl/Controls/TimePickerDemoCtl.xaml.cs
@@ -1,9 +1,5 @@
-// ReSharper disable once CheckNamespace
-namespace HandyControlDemo.UserControl
+namespace HandyControlDemo.UserControl
{
- ///
- /// TimePickerDemoCtl.xaml 的交互逻辑
- ///
public partial class TimePickerDemoCtl
{
public TimePickerDemoCtl()
diff --git a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
index f18a2734..fd426cf5 100644
--- a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
+++ b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
@@ -144,16 +144,31 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -164,11 +179,6 @@
-
-
-
-
-