123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- 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<DependencyProperty, bool> _isHandlerSuspended;
- #endregion Data
- #region Public Events
- public static readonly RoutedEvent SelectedDateTimeChangedEvent =
- EventManager.RegisterRoutedEvent("SelectedDateTimeChanged", RoutingStrategy.Direct,
- typeof(EventHandler<FunctionEventArgs<DateTime?>>), typeof(CalendarWithClock));
- public event EventHandler<FunctionEventArgs<DateTime?>> SelectedDateTimeChanged
- {
- add => AddHandler(SelectedDateTimeChangedEvent, value);
- remove => RemoveHandler(SelectedDateTimeChangedEvent, value);
- }
- public event EventHandler<FunctionEventArgs<DateTime>> 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(
- nameof(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(
- nameof(ShowConfirmButton), typeof(bool), typeof(CalendarWithClock), new PropertyMetadata(ValueBoxes.FalseBox));
- public bool ShowConfirmButton
- {
- get => (bool) GetValue(ShowConfirmButtonProperty);
- set => SetValue(ShowConfirmButtonProperty, ValueBoxes.BooleanBox(value));
- }
- public static readonly DependencyProperty SelectedDateTimeProperty = DependencyProperty.Register(
- nameof(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<DateTime?>(SelectedDateTimeChangedEvent, ctl)
- {
- Info = v
- });
- }
- public DateTime? SelectedDateTime
- {
- get => (DateTime?) GetValue(SelectedDateTimeProperty);
- set => SetValue(SelectedDateTimeProperty, value);
- }
- public static readonly DependencyProperty DisplayDateTimeProperty = DependencyProperty.Register(
- nameof(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._calendar.DisplayDate = v;
- ctl.OnDisplayDateTimeChanged(new FunctionEventArgs<DateTime>(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<DateTime?> e) => RaiseEvent(e);
- protected virtual void OnDisplayDateTimeChanged(FunctionEventArgs<DateTime> e)
- {
- var handler = DisplayDateTimeChanged;
- handler?.Invoke(this, e);
- }
- #endregion Protected Methods
- #region Private Methods
- private void SetIsHandlerSuspended(DependencyProperty property, bool value)
- {
- if (value)
- {
- _isHandlerSuspended ??= new Dictionary<DependencyProperty, bool>(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<DateTime> 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
- }
|