From 26aeab35ee934ef49acc21f52cf265ca009de968 Mon Sep 17 00:00:00 2001 From: chinboy Date: Wed, 27 Aug 2025 14:43:53 +0800 Subject: [PATCH] Refactor DatePicker Bindings --- src/AtomUI.Controls/Calendar/CalendarItem.cs | 17 ++--- .../DatePicker/CalendarView/CalendarItem.cs | 23 ++++--- .../CalendarView/DualMonthCalendarItem.cs | 10 ++- src/AtomUI.Controls/DatePicker/DatePicker.cs | 18 ++++-- .../DatePicker/DatePickerFlyout.cs | 21 +++--- .../DatePicker/RangeDatePicker.cs | 19 +++--- .../DatePicker/RangeDatePickerFlyout.cs | 64 ++++++++++--------- .../CalendarView/CalendarItemTheme.axaml | 1 - 8 files changed, 97 insertions(+), 76 deletions(-) diff --git a/src/AtomUI.Controls/Calendar/CalendarItem.cs b/src/AtomUI.Controls/Calendar/CalendarItem.cs index 4864d4fb7..2875a023d 100644 --- a/src/AtomUI.Controls/Calendar/CalendarItem.cs +++ b/src/AtomUI.Controls/Calendar/CalendarItem.cs @@ -4,8 +4,6 @@ using System.Reactive.Disposables; using AtomUI.Collections.Pooled; using AtomUI.Controls.Themes; using AtomUI.Data; -using AtomUI.Theme.Data; -using AtomUI.Theme.Styling; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; @@ -66,11 +64,11 @@ internal class CalendarItem : TemplatedControl o => o.IsMonthViewMode, (o, v) => o.IsMonthViewMode = v); - public static readonly StyledProperty DayTitleHeightProperty = + internal static readonly StyledProperty DayTitleHeightProperty = AvaloniaProperty.Register( nameof(DayTitleHeight)); - public static readonly StyledProperty IsMotionEnabledProperty = + internal static readonly StyledProperty IsMotionEnabledProperty = MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); /// @@ -282,18 +280,10 @@ internal class CalendarItem : TemplatedControl { var childCount = Calendar.RowsPerMonth + Calendar.RowsPerMonth * Calendar.ColumnsPerMonth; using var children = new PooledList(childCount); - - _dayBtnBindingDisposables?.Dispose(); - _dayBtnBindingDisposables = new CompositeDisposable(Calendar.RowsPerMonth * Calendar.ColumnsPerMonth + Calendar.ColumnsPerMonth); for (var i = 0; i < Calendar.ColumnsPerMonth; i++) { var cell = DayTitleTemplate?.Build(); - if (cell is TextBlock textBlockCell) - { - _dayBtnBindingDisposables.Add(TokenResourceBinder.CreateTokenBinding(textBlockCell, - HeightProperty, CalendarTokenKey.DayTitleHeight)); - } if (cell is not null) { cell.DataContext = string.Empty; @@ -302,6 +292,9 @@ internal class CalendarItem : TemplatedControl children.Add(cell); } } + + _dayBtnBindingDisposables?.Dispose(); + _dayBtnBindingDisposables = new CompositeDisposable(Calendar.RowsPerMonth * Calendar.ColumnsPerMonth); EventHandler cellMouseLeftButtonDown = HandleCellMouseLeftButtonDown; EventHandler cellMouseLeftButtonUp = HandleCellMouseLeftButtonUp; diff --git a/src/AtomUI.Controls/DatePicker/CalendarView/CalendarItem.cs b/src/AtomUI.Controls/DatePicker/CalendarView/CalendarItem.cs index f6ac551ee..17d9d8240 100644 --- a/src/AtomUI.Controls/DatePicker/CalendarView/CalendarItem.cs +++ b/src/AtomUI.Controls/DatePicker/CalendarView/CalendarItem.cs @@ -27,8 +27,7 @@ namespace AtomUI.Controls.CalendarView; [TemplatePart(CalendarItemThemeConstants.NextButtonPart, typeof(IconButton))] [TemplatePart(CalendarItemThemeConstants.NextMonthButtonPart, typeof(IconButton))] [TemplatePart(CalendarItemThemeConstants.YearViewPart, typeof(Grid))] -internal class CalendarItem : TemplatedControl, - IResourceBindingManager +internal class CalendarItem : TemplatedControl, IResourceBindingManager { internal const string CalendarDisabledPC = ":calendardisabled"; @@ -70,8 +69,8 @@ internal class CalendarItem : TemplatedControl, o => o.IsMonthViewMode, (o, v) => o.IsMonthViewMode = v); - internal static readonly StyledProperty IsMotionEnabledProperty - = MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); + internal static readonly StyledProperty IsMotionEnabledProperty = + MotionAwareControlProperty.IsMotionEnabledProperty.AddOwner(); private bool _isMonthViewMode = true; @@ -237,6 +236,9 @@ internal class CalendarItem : TemplatedControl, /// Gets the Grid that hosts the content when in year or decade mode. /// internal Grid? YearView { get; set; } + + private protected CompositeDisposable? DayBtnBindingDisposables; + private protected CompositeDisposable? MonthBtnBindingDisposables; private void PopulateGrids() { @@ -250,6 +252,9 @@ internal class CalendarItem : TemplatedControl, EventHandler monthCalendarButtonMouseDown = HandleMonthCalendarButtonMouseDown; EventHandler monthCalendarButtonMouseUp = HandleMonthCalendarButtonMouseUp; EventHandler monthMouseEntered = HandleMonthMouseEntered; + + MonthBtnBindingDisposables?.Dispose(); + MonthBtnBindingDisposables = new CompositeDisposable(Calendar.RowsPerYear * Calendar.ColumnsPerYear); for (var i = 0; i < Calendar.RowsPerYear; i++) { @@ -260,8 +265,8 @@ internal class CalendarItem : TemplatedControl, if (Owner != null) { month.Owner = Owner; - BindUtils.RelayBind(Owner, Calendar.IsMotionEnabledProperty, month, - CalendarButton.IsMotionEnabledProperty); + MonthBtnBindingDisposables.Add(BindUtils.RelayBind(Owner, Calendar.IsMotionEnabledProperty, month, + CalendarButton.IsMotionEnabledProperty)); } month.SetValue(Grid.RowProperty, i); @@ -281,6 +286,8 @@ internal class CalendarItem : TemplatedControl, { if (MonthView != null) { + DayBtnBindingDisposables?.Dispose(); + DayBtnBindingDisposables = new CompositeDisposable(Calendar.RowsPerMonth * Calendar.ColumnsPerMonth); PopulateMonthViewGrid(MonthView); } } @@ -316,8 +323,8 @@ internal class CalendarItem : TemplatedControl, if (Owner != null) { cell.Owner = Owner; - BindUtils.RelayBind(Owner, Calendar.IsMotionEnabledProperty, cell, - CalendarDayButton.IsMotionEnabledProperty); + DayBtnBindingDisposables?.Add(BindUtils.RelayBind(Owner, Calendar.IsMotionEnabledProperty, cell, + CalendarDayButton.IsMotionEnabledProperty)); } cell.SetValue(Grid.RowProperty, i); diff --git a/src/AtomUI.Controls/DatePicker/CalendarView/DualMonthCalendarItem.cs b/src/AtomUI.Controls/DatePicker/CalendarView/DualMonthCalendarItem.cs index 329152237..efaf27076 100644 --- a/src/AtomUI.Controls/DatePicker/CalendarView/DualMonthCalendarItem.cs +++ b/src/AtomUI.Controls/DatePicker/CalendarView/DualMonthCalendarItem.cs @@ -1,4 +1,5 @@ -using AtomUI.Controls.Themes; +using System.Reactive.Disposables; +using AtomUI.Controls.Themes; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; @@ -217,7 +218,12 @@ internal class DualMonthCalendarItem : RangeCalendarItem protected override void PopulateMonthViewsGrid() { - base.PopulateMonthViewsGrid(); + DayBtnBindingDisposables?.Dispose(); + DayBtnBindingDisposables = new CompositeDisposable(Calendar.RowsPerMonth * Calendar.ColumnsPerMonth * 2); + if (MonthView != null) + { + PopulateMonthViewGrid(MonthView); + } if (SecondaryMonthView != null) { PopulateMonthViewGrid(SecondaryMonthView); diff --git a/src/AtomUI.Controls/DatePicker/DatePicker.cs b/src/AtomUI.Controls/DatePicker/DatePicker.cs index cb1f69889..b5673d1a8 100644 --- a/src/AtomUI.Controls/DatePicker/DatePicker.cs +++ b/src/AtomUI.Controls/DatePicker/DatePicker.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Reactive.Disposables; using AtomUI.Controls.CalendarView; using AtomUI.Controls.Primitives; using AtomUI.Controls.TimePickerLang; @@ -100,6 +101,7 @@ public class DatePicker : InfoPickerInput, } private DatePickerPresenter? _pickerPresenter; + private CompositeDisposable? _flyoutBindingDisposables; /// /// 清除时间选择器的值,不考虑默认值 @@ -164,13 +166,15 @@ public class DatePicker : InfoPickerInput, { var flyout = new DatePickerFlyout(); flyout.IsDetectMouseClickEnabled = false; - BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, DatePickerFlyout.IsMotionEnabledProperty); - BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, DatePickerPresenter.IsMotionEnabledProperty); - BindUtils.RelayBind(this, SelectedDateTimeProperty, flyout, DatePickerPresenter.SelectedDateTimeProperty); - BindUtils.RelayBind(this, IsNeedConfirmProperty, flyout, DatePickerPresenter.IsNeedConfirmProperty); - BindUtils.RelayBind(this, IsShowNowProperty, flyout, DatePickerPresenter.IsShowNowProperty); - BindUtils.RelayBind(this, IsShowTimeProperty, flyout, DatePickerPresenter.IsShowTimeProperty); - BindUtils.RelayBind(this, ClockIdentifierProperty, flyout, DatePickerPresenter.ClockIdentifierProperty); + _flyoutBindingDisposables?.Dispose(); + _flyoutBindingDisposables = new CompositeDisposable(7); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, DatePickerFlyout.IsMotionEnabledProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, DatePickerPresenter.IsMotionEnabledProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, SelectedDateTimeProperty, flyout, DatePickerPresenter.SelectedDateTimeProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsNeedConfirmProperty, flyout, DatePickerPresenter.IsNeedConfirmProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsShowNowProperty, flyout, DatePickerPresenter.IsShowNowProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsShowTimeProperty, flyout, DatePickerPresenter.IsShowTimeProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, ClockIdentifierProperty, flyout, DatePickerPresenter.ClockIdentifierProperty)); return flyout; } diff --git a/src/AtomUI.Controls/DatePicker/DatePickerFlyout.cs b/src/AtomUI.Controls/DatePicker/DatePickerFlyout.cs index f16375d4d..b6beccfbc 100644 --- a/src/AtomUI.Controls/DatePicker/DatePickerFlyout.cs +++ b/src/AtomUI.Controls/DatePicker/DatePickerFlyout.cs @@ -1,4 +1,5 @@ -using AtomUI.Data; +using System.Reactive.Disposables; +using AtomUI.Data; using Avalonia; using Avalonia.Controls; @@ -52,23 +53,25 @@ internal class DatePickerFlyout : Flyout } internal DatePickerPresenter? DatePickerPresenter { get; set; } + private CompositeDisposable? _presenterBindingDisposables; protected override Control CreatePresenter() { DatePickerPresenter = new DatePickerPresenter(); - - BindUtils.RelayBind(this, IsMotionEnabledProperty, DatePickerPresenter, DatePickerPresenter.IsMotionEnabledProperty); - BindUtils.RelayBind(this, SelectedDateTimeProperty, DatePickerPresenter, DatePickerPresenter.SelectedDateTimeProperty); - BindUtils.RelayBind(this, IsNeedConfirmProperty, DatePickerPresenter, DatePickerPresenter.IsNeedConfirmProperty); - BindUtils.RelayBind(this, IsShowNowProperty, DatePickerPresenter, DatePickerPresenter.IsShowNowProperty); - BindUtils.RelayBind(this, IsShowTimeProperty, DatePickerPresenter, DatePickerPresenter.IsShowTimeProperty); - BindUtils.RelayBind(this, ClockIdentifierProperty, DatePickerPresenter, DatePickerPresenter.ClockIdentifierProperty); + _presenterBindingDisposables?.Dispose(); + _presenterBindingDisposables = new CompositeDisposable(7); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsMotionEnabledProperty, DatePickerPresenter, DatePickerPresenter.IsMotionEnabledProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, SelectedDateTimeProperty, DatePickerPresenter, DatePickerPresenter.SelectedDateTimeProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsNeedConfirmProperty, DatePickerPresenter, DatePickerPresenter.IsNeedConfirmProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowNowProperty, DatePickerPresenter, DatePickerPresenter.IsShowNowProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowTimeProperty, DatePickerPresenter, DatePickerPresenter.IsShowTimeProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, ClockIdentifierProperty, DatePickerPresenter, DatePickerPresenter.ClockIdentifierProperty)); var flyoutPresenter = new FlyoutPresenter { Content = DatePickerPresenter }; - BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, flyoutPresenter, IsShowArrowProperty); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, flyoutPresenter, IsShowArrowProperty)); CalculateShowArrowEffective(); SetupArrowPosition(Popup, flyoutPresenter); diff --git a/src/AtomUI.Controls/DatePicker/RangeDatePicker.cs b/src/AtomUI.Controls/DatePicker/RangeDatePicker.cs index cd8043072..bedc8b667 100644 --- a/src/AtomUI.Controls/DatePicker/RangeDatePicker.cs +++ b/src/AtomUI.Controls/DatePicker/RangeDatePicker.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Reactive.Disposables; using AtomUI.Controls.CalendarView; using AtomUI.Controls.Primitives; using AtomUI.Controls.TimePickerLang; @@ -117,6 +118,7 @@ public class RangeDatePicker : RangeInfoPickerInput, private RangeDatePickerPresenter? _pickerPresenter; private bool? _isNeedConfirmedBackup; + private CompositeDisposable? _flyoutBindingDisposables; public RangeDatePicker() { @@ -127,14 +129,15 @@ public class RangeDatePicker : RangeInfoPickerInput, { var flyout = new RangeDatePickerFlyout(); flyout.IsDetectMouseClickEnabled = false; - BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, RangeDatePickerFlyout.IsMotionEnabledProperty); - - BindUtils.RelayBind(this, RangeStartSelectedDateProperty, flyout, RangeDatePickerFlyout.SelectedDateTimeProperty); - BindUtils.RelayBind(this, RangeEndSelectedDateProperty, flyout, RangeDatePickerFlyout.SecondarySelectedDateTimeProperty); - BindUtils.RelayBind(this, ClockIdentifierProperty, flyout, RangeDatePickerFlyout.ClockIdentifierProperty); - BindUtils.RelayBind(this, IsNeedConfirmProperty, flyout, RangeDatePickerFlyout.IsNeedConfirmProperty); - BindUtils.RelayBind(this, IsShowNowProperty, flyout, RangeDatePickerFlyout.IsShowNowProperty); - BindUtils.RelayBind(this, IsShowTimeProperty, flyout, RangeDatePickerFlyout.IsShowTimeProperty); + _flyoutBindingDisposables?.Dispose(); + _flyoutBindingDisposables = new CompositeDisposable(7); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsMotionEnabledProperty, flyout, RangeDatePickerFlyout.IsMotionEnabledProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, RangeStartSelectedDateProperty, flyout, RangeDatePickerFlyout.SelectedDateTimeProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, RangeEndSelectedDateProperty, flyout, RangeDatePickerFlyout.SecondarySelectedDateTimeProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, ClockIdentifierProperty, flyout, RangeDatePickerFlyout.ClockIdentifierProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsNeedConfirmProperty, flyout, RangeDatePickerFlyout.IsNeedConfirmProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsShowNowProperty, flyout, RangeDatePickerFlyout.IsShowNowProperty)); + _flyoutBindingDisposables.Add(BindUtils.RelayBind(this, IsShowTimeProperty, flyout, RangeDatePickerFlyout.IsShowTimeProperty)); return flyout; } diff --git a/src/AtomUI.Controls/DatePicker/RangeDatePickerFlyout.cs b/src/AtomUI.Controls/DatePicker/RangeDatePickerFlyout.cs index 807dee2bf..01736c7fe 100644 --- a/src/AtomUI.Controls/DatePicker/RangeDatePickerFlyout.cs +++ b/src/AtomUI.Controls/DatePicker/RangeDatePickerFlyout.cs @@ -1,4 +1,5 @@ -using AtomUI.Data; +using System.Reactive.Disposables; +using AtomUI.Data; using Avalonia; using Avalonia.Controls; @@ -16,45 +17,47 @@ internal class RangeDatePickerFlyout : DatePickerFlyout } internal FlyoutPresenter? _flyoutPresenter; - + private CompositeDisposable? _flyoutPresenterBindingDisposables; + private CompositeDisposable? _presenterBindingDisposables; protected override Control CreatePresenter() { _flyoutPresenter = new FlyoutPresenter(); - ConfigureDatePickerPresenter(); - BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, _flyoutPresenter, IsShowArrowProperty); + _flyoutPresenterBindingDisposables?.Dispose(); + _flyoutPresenterBindingDisposables = new CompositeDisposable(1); + ConfigureDatePickerPresenter(_flyoutPresenter); + _flyoutPresenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, _flyoutPresenter, IsShowArrowProperty)); CalculateShowArrowEffective(); SetupArrowPosition(Popup, _flyoutPresenter); return _flyoutPresenter; } - private void ConfigureDatePickerPresenter() + private void ConfigureDatePickerPresenter(FlyoutPresenter flyoutPresenter) { - if (_flyoutPresenter != null) + _presenterBindingDisposables?.Dispose(); + _presenterBindingDisposables = new CompositeDisposable(7); + DatePickerPresenter? presenter; + if (IsShowTime) { - DatePickerPresenter? presenter; - if (IsShowTime) + presenter = new TimedRangeDatePickerPresenter() { - presenter = new TimedRangeDatePickerPresenter() - { - IsShowTime = true - }; - } - else - { - presenter = new DualMonthRangeDatePickerPresenter(); - } - - BindUtils.RelayBind(this, IsMotionEnabledProperty, presenter, RangeDatePickerPresenter.IsMotionEnabledProperty); - BindUtils.RelayBind(this, SelectedDateTimeProperty, presenter, RangeDatePickerPresenter.SelectedDateTimeProperty); - BindUtils.RelayBind(this, IsNeedConfirmProperty, presenter, RangeDatePickerPresenter.IsNeedConfirmProperty); - BindUtils.RelayBind(this, IsShowNowProperty, presenter, RangeDatePickerPresenter.IsShowNowProperty); - BindUtils.RelayBind(this, IsShowTimeProperty, presenter, RangeDatePickerPresenter.IsShowTimeProperty); - BindUtils.RelayBind(this, ClockIdentifierProperty, presenter, RangeDatePickerPresenter.ClockIdentifierProperty); - BindUtils.RelayBind(this, SecondarySelectedDateTimeProperty, presenter, RangeDatePickerPresenter.SecondarySelectedDateTimeProperty); - - _flyoutPresenter.Content = presenter; - DatePickerPresenter = presenter; + IsShowTime = true + }; } + else + { + presenter = new DualMonthRangeDatePickerPresenter(); + } + + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsMotionEnabledProperty, presenter, RangeDatePickerPresenter.IsMotionEnabledProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, SelectedDateTimeProperty, presenter, RangeDatePickerPresenter.SelectedDateTimeProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsNeedConfirmProperty, presenter, RangeDatePickerPresenter.IsNeedConfirmProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowNowProperty, presenter, RangeDatePickerPresenter.IsShowNowProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowTimeProperty, presenter, RangeDatePickerPresenter.IsShowTimeProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, ClockIdentifierProperty, presenter, RangeDatePickerPresenter.ClockIdentifierProperty)); + _presenterBindingDisposables.Add(BindUtils.RelayBind(this, SecondarySelectedDateTimeProperty, presenter, RangeDatePickerPresenter.SecondarySelectedDateTimeProperty)); + + flyoutPresenter.Content = presenter; + DatePickerPresenter = presenter; } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) @@ -62,7 +65,10 @@ internal class RangeDatePickerFlyout : DatePickerFlyout base.OnPropertyChanged(e); if (e.Property == IsShowTimeProperty) { - ConfigureDatePickerPresenter(); + if (_flyoutPresenter != null) + { + ConfigureDatePickerPresenter(_flyoutPresenter); + } } } } \ No newline at end of file diff --git a/src/AtomUI.Controls/DatePicker/Themes/CalendarView/CalendarItemTheme.axaml b/src/AtomUI.Controls/DatePicker/Themes/CalendarView/CalendarItemTheme.axaml index 5108a37fa..0cbff6973 100644 --- a/src/AtomUI.Controls/DatePicker/Themes/CalendarView/CalendarItemTheme.axaml +++ b/src/AtomUI.Controls/DatePicker/Themes/CalendarView/CalendarItemTheme.axaml @@ -43,7 +43,6 @@