using System.Globalization; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; using Irihi.Avalonia.Shared.Common; using Irihi.Avalonia.Shared.Contracts; using Irihi.Avalonia.Shared.Helpers; using Calendar = Avalonia.Controls.Calendar; namespace Ursa.Controls; [TemplatePart(PART_Button, typeof(Button))] [TemplatePart(PART_Popup, typeof(Popup))] [TemplatePart(PART_StartCalendar, typeof(CalendarView))] [TemplatePart(PART_EndCalendar, typeof(CalendarView))] [TemplatePart(PART_StartTextBox, typeof(TextBox))] [TemplatePart(PART_EndTextBox, typeof(TextBox))] [PseudoClasses(PseudoClassName.PC_Empty)] public class DateRangePicker : DatePickerBase, IClearControl { public const string PART_Button = "PART_Button"; public const string PART_Popup = "PART_Popup"; public const string PART_StartCalendar = "PART_StartCalendar"; public const string PART_EndCalendar = "PART_EndCalendar"; public const string PART_StartTextBox = "PART_StartTextBox"; public const string PART_EndTextBox = "PART_EndTextBox"; public static readonly StyledProperty SelectedStartDateProperty = AvaloniaProperty.Register( nameof(SelectedStartDate), defaultBindingMode: BindingMode.TwoWay); public static readonly StyledProperty SelectedEndDateProperty = AvaloniaProperty.Register( nameof(SelectedEndDate), defaultBindingMode: BindingMode.TwoWay); public static readonly StyledProperty EnableMonthSyncProperty = AvaloniaProperty.Register( nameof(EnableMonthSync)); private Button? _button; private CalendarView? _endCalendar; private TextBox? _endTextBox; private DateTime? _previewEnd; private DateTime? _previewStart; private bool? _start; private CalendarView? _startCalendar; private TextBox? _startTextBox; private Popup? _popup; static DateRangePicker() { FocusableProperty.OverrideDefaultValue(true); SelectedStartDateProperty.Changed.AddClassHandler((picker, args) => picker.OnSelectionChanged(args)); SelectedEndDateProperty.Changed.AddClassHandler((picker, args) => picker.OnSelectionChanged(args)); } public bool EnableMonthSync { get => GetValue(EnableMonthSyncProperty); set => SetValue(EnableMonthSyncProperty, value); } public DateTime? SelectedStartDate { get => GetValue(SelectedStartDateProperty); set => SetValue(SelectedStartDateProperty, value); } public DateTime? SelectedEndDate { get => GetValue(SelectedEndDateProperty); set => SetValue(SelectedEndDateProperty, value); } public void Clear() { SetCurrentValue(SelectedStartDateProperty, null); SetCurrentValue(SelectedEndDateProperty, null); } private void OnSelectionChanged(AvaloniaPropertyChangedEventArgs args) { if (args.Property == SelectedStartDateProperty) { if (args.NewValue.Value is null) { _startCalendar?.ClearSelection(); _startTextBox?.Clear(); } else { _startCalendar?.MarkDates(args.NewValue.Value, args.NewValue.Value); _startTextBox?.SetValue(TextBox.TextProperty, args.NewValue.Value.Value.ToString(DisplayFormat ?? "yyyy-MM-dd")); } } else if (args.Property == SelectedEndDateProperty) { if (args.NewValue.Value is null) { _endCalendar?.ClearSelection(); _endTextBox?.Clear(); } else { _endCalendar?.MarkDates(args.NewValue.Value, args.NewValue.Value); _endTextBox?.SetValue(TextBox.TextProperty, args.NewValue.Value.Value.ToString(DisplayFormat ?? "yyyy-MM-dd")); } } PseudoClasses.Set(PseudoClassName.PC_Empty, SelectedStartDate is null && SelectedEndDate is null); } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); GotFocusEvent.RemoveHandler(OnTextBoxGetFocus, _startTextBox, _endTextBox); TextBox.TextChangedEvent.RemoveHandler(OnTextChanged, _startTextBox, _endTextBox); PointerPressedEvent.RemoveHandler(OnTextBoxPointerPressed, _startTextBox, _endTextBox); Button.ClickEvent.RemoveHandler(OnButtonClick, _button); LostFocusEvent.RemoveHandler(OnTextBoxLostFocus, _startTextBox, _endTextBox); if (_startCalendar != null) { _startCalendar.DateSelected -= OnDateSelected; _startCalendar.DatePreviewed -= OnDatePreviewed; _startCalendar.ContextDateChanged -= OnContextDateChanged; } if (_endCalendar != null) { _endCalendar.DateSelected -= OnDateSelected; _endCalendar.DatePreviewed -= OnDatePreviewed; _endCalendar.ContextDateChanged -= OnContextDateChanged; } _button = e.NameScope.Find