|
- using BPA.UIControl.Commons.KnownBoxes;
- using System;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Controls.Primitives;
- using System.Windows.Data;
- using System.Windows.Input;
- using System.Windows.Threading;
-
- namespace BPA.UIControl
- {
- /// <summary>
- /// 日期时间选择器
- /// </summary>
- [TemplatePart(Name = TextBoxPartName, Type = typeof(TextBox))]
- [TemplatePart(Name = CurrentTextBoxPartName, Type = typeof(TextBox))]
- [TemplatePart(Name = PopupPartName, Type = typeof(Popup))]
- [TemplatePart(Name = ButtonPartName, Type = typeof(Button))]
- [TemplatePart(Name = ClockPartName, Type = typeof(Clock))]
- [TemplatePart(Name = CalendarPartName, Type = typeof(Calendar))]
- [TemplatePart(Name = ConfirmButtonPartName, Type = typeof(Button))]
- public class DateTimePicker : Control
- {
- const string TextBoxPartName = "PART_TextBox";
- const string PopupPartName = "PART_Popup";
- const string ButtonPartName = "PART_Button";
- const string ClockPartName = "PART_Clock";
- const string CalendarPartName = "PART_Calendar";
- const string ConfirmButtonPartName = "PART_ConfirmButton";
- const string CurrentTextBoxPartName = "PART_CurrentTextBox";
-
- private TextBox _textBox;
- private Popup _popup;
- private Clock _clock;
- private Calendar _calendar;
- private Button _confirmButton;
-
- private bool isInternalSetting = true;
- private DateTime currentDateTime;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DateTimePicker"/> class.
- /// </summary>
- static DateTimePicker()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(DateTimePicker), new FrameworkPropertyMetadata(typeof(DateTimePicker)));
- }
-
- /// <inheritdoc/>
- public override void OnApplyTemplate()
- {
- base.OnApplyTemplate();
-
- Clock clock = GetTemplateChild(ClockPartName) as Clock;
- clock.CurrentTimeChanged += Clock_SelectedTimeChanged;
- this._clock = clock;
-
- Calendar calendar = GetTemplateChild(CalendarPartName) as Calendar;
- calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
- this._calendar = calendar;
-
- TextBox textBox = GetTemplateChild(TextBoxPartName) as TextBox;
- Binding binding1 = new Binding("Text");
- binding1.Source = this;
- binding1.Mode = BindingMode.TwoWay;
- textBox.SetBinding(TextBox.TextProperty, binding1);
- _textBox = textBox;
-
- Popup popup = GetTemplateChild(PopupPartName) as Popup;
- popup.Closed += Popup_Closed;
- popup.Opened += Popup_Opened;
- if (IsDropDownOpen)
- {
- _popup.IsOpen = true;
- }
- _popup = popup;
-
- Button button = GetTemplateChild(ButtonPartName) as Button;
- button.Click += Button_Click;
-
- Button confirmButton = GetTemplateChild(ConfirmButtonPartName) as Button;
- confirmButton.Click += ConfirmButton_Click;
- _confirmButton = confirmButton;
-
- currentDateTime = SelectedDateTime == null ? DateTime.Now : SelectedDateTime.Value;
- }
-
- #region 路由事件
-
- /// <summary>
- /// 选择时间改变事件
- /// </summary>
- public static readonly RoutedEvent SelectedTimeChangedEvent =
- EventManager.RegisterRoutedEvent("SelectedTimeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<DateTime?>), typeof(DateTimePicker));
-
- /// <summary>
- /// 选择时间改变事件处理
- /// </summary>
- public event RoutedPropertyChangedEventHandler<DateTime?> SelectedTimeChanged
- {
- add { AddHandler(SelectedTimeChangedEvent, value); }
- remove { RemoveHandler(SelectedTimeChangedEvent, value); }
- }
-
- #endregion 路由事件
-
- #region 依赖属性
-
- /// <summary>
- /// 选择的日期时间
- /// </summary>
- public static readonly DependencyProperty SelectedDateTimeProperty = DependencyProperty.Register(
- "SelectedDateTime", typeof(DateTime?), typeof(DateTimePicker), new FrameworkPropertyMetadata(default(DateTime?), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedTimeChanged));
-
- /// <summary>
- /// 选择的日期时间
- /// </summary>
- public DateTime? SelectedDateTime
- {
- get { return (DateTime?)GetValue(SelectedDateTimeProperty); }
- set { SetValue(SelectedDateTimeProperty, value); }
- }
-
- /// <summary>
- /// 是否下拉打开
- /// </summary>
- public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
- "IsDropDownOpen", typeof(bool), typeof(DateTimePicker), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsDropDownOpenChanged));
-
- /// <summary>
- /// 是否下拉打开
- /// </summary>
- public bool IsDropDownOpen
- {
- get { return (bool)GetValue(IsDropDownOpenProperty); }
- set { SetValue(IsDropDownOpenProperty, BooleanBoxes.Box(value)); }
- }
-
- /// <summary>
- /// Ons the is drop down open changed.
- /// </summary>
- /// <param name="d">The d.</param>
- /// <param name="e">The e.</param>
- private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- DateTimePicker tp = d as DateTimePicker;
- bool newValue = (bool)e.NewValue;
- if (tp._popup != null && tp._popup.IsOpen != newValue)
- {
- tp._popup.IsOpen = newValue;
- if (newValue)
- {
- tp.Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate ()
- {
- tp._clock.Focus();
- });
- }
- }
- }
-
- /// <summary>
- /// 显示文本
- /// </summary>
- public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
- "Text", typeof(string), typeof(DateTimePicker), new PropertyMetadata(null, OnTextChanged));
-
- /// <summary>
- /// 显示文本
- /// </summary>
- public string Text
- {
- get { return (string)GetValue(TextProperty); }
- set { SetValue(TextProperty, value); }
- }
-
- /// <summary>
- /// 时间文本改变
- /// </summary>
- private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- DateTimePicker dateTimePicker = (DateTimePicker)d;
-
- var oldDateTime = dateTimePicker.SelectedDateTime?.ToString(dateTimePicker.SelectedDateTimeFormat);
- if (oldDateTime != dateTimePicker.Text)
- {
- if (DateTime.TryParse(dateTimePicker.Text, out DateTime result))
- {
- dateTimePicker.SelectedDateTime = result;
- dateTimePicker.currentDateTime = result;
- }
- else if (string.IsNullOrEmpty(dateTimePicker.Text))
- {
- dateTimePicker.SelectedDateTime = null;
- }
- else
- {
- dateTimePicker.Text = oldDateTime;
- }
- }
- }
-
- /// <summary>
- /// 选择时间格式化
- /// </summary>
- public static readonly DependencyProperty SelectedDateTimeFormatProperty = DependencyProperty.Register(
- "SelectedDateTimeFormat", typeof(string), typeof(DateTimePicker), new PropertyMetadata(default(string), OnSelectedDateTimeFormatChanged));
-
- private static void OnSelectedDateTimeFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- if (d is DateTimePicker picker)
- {
- picker.Text = picker.SelectedDateTime?.ToString(picker.SelectedDateTimeFormat);
- }
- }
-
- /// <summary>
- /// 选择时间格式化
- /// </summary>
- public string SelectedDateTimeFormat
- {
- get { return (string)GetValue(SelectedDateTimeFormatProperty); }
- set { SetValue(SelectedDateTimeFormatProperty, value); }
- }
-
- #endregion 依赖属性
-
- #region 方法
-
- /// <summary>
- /// 文本鼠标点下
- /// </summary>
- private void TextBox_MouseDown(object sender, MouseButtonEventArgs e)
- {
- TextBox textBox = sender as TextBox;
- textBox.Focus();
- }
-
- /// <summary>
- /// 选择时间改变
- /// </summary>
- private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- if (d is DateTimePicker dateTimePicker)
- {
- dateTimePicker.Text = dateTimePicker.SelectedDateTime?.ToString(dateTimePicker.SelectedDateTimeFormat);
-
- var args = new RoutedPropertyChangedEventArgs<DateTime?>((DateTime?)e.OldValue, (DateTime?)e.NewValue);
- args.RoutedEvent = DateTimePicker.SelectedTimeChangedEvent;
- dateTimePicker.RaiseEvent(args);
-
- dateTimePicker.currentDateTime = dateTimePicker.SelectedDateTime == null ? DateTime.Now : dateTimePicker.SelectedDateTime.Value;
-
- dateTimePicker._textBox?.Focus();
- dateTimePicker._textBox?.SelectAll();
- }
- }
-
- /// <summary>
- /// 时钟的时间改变
- /// </summary>
- private void Clock_SelectedTimeChanged(object sender, RoutedPropertyChangedEventArgs<DateTime?> e)
- {
- if (isInternalSetting)
- {
- return;
- }
-
- if (SelectedDateTime != null)
- {
- DateTime dateTime = (DateTime)SelectedDateTime;
- DateTime newDate = (DateTime)e.NewValue;
- currentDateTime = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, newDate.Hour, newDate.Minute, newDate.Second);
- }
- else
- {
- currentDateTime = e.NewValue.Value;
- }
-
- }
-
- /// <summary>
- /// 日期改变
- /// </summary>
- private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
- {
- if (isInternalSetting)
- {
- return;
- }
-
- if (SelectedDateTime != null)
- {
- DateTime dateTime = (DateTime)SelectedDateTime;
- DateTime newTime = (DateTime)_calendar.SelectedDate;
- currentDateTime = new DateTime(newTime.Year, newTime.Month, newTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second);
- }
- else
- {
- var time = _clock.CurrentTime == null ? TimeSpan.Zero : _clock.CurrentTime.Value.TimeOfDay;
- currentDateTime = (DateTime)_calendar.SelectedDate + time;
- }
-
- Mouse.Capture(null);
- }
-
- /// <summary>
- /// 点击时间按钮
- /// </summary>
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- Text = _textBox.Text;
- IsDropDownOpen = !IsDropDownOpen;
- }
-
- /// <summary>
- /// popup 打开后
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void Popup_Opened(object sender, EventArgs e)
- {
- isInternalSetting = true;
- _calendar.SelectedDate = currentDateTime.Date;
- _calendar.DisplayDate = currentDateTime.Date;
- _clock.SelectedTime = currentDateTime;
- isInternalSetting = false;
- }
-
- /// <summary>
- /// popup 关闭
- /// </summary>
- private void Popup_Closed(object sender, EventArgs e)
- {
- if (_confirmButton.IsKeyboardFocusWithin)
- {
- _textBox.Focus();
- }
- else
- {
- IsDropDownOpen = false;
- }
- }
-
- /// <summary>
- /// 确定
- /// </summary>
- private void ConfirmButton_Click(object sender, RoutedEventArgs e)
- {
- SelectedDateTime = currentDateTime;
- IsDropDownOpen = false;
-
- var args = new RoutedPropertyChangedEventArgs<DateTime?>(SelectedDateTime, SelectedDateTime);
- args.RoutedEvent = DateTimePicker.SelectedTimeChangedEvent;
- RaiseEvent(args);
- }
-
- #endregion 方法
- }
- }
|