diff --git a/src/AtomUI.Controls/ButtonSpinner/ButtonSpinnerInnerBox.cs b/src/AtomUI.Controls/ButtonSpinner/ButtonSpinnerInnerBox.cs index 291d902fc..78fbaa14c 100644 --- a/src/AtomUI.Controls/ButtonSpinner/ButtonSpinnerInnerBox.cs +++ b/src/AtomUI.Controls/ButtonSpinner/ButtonSpinnerInnerBox.cs @@ -1,6 +1,5 @@ using AtomUI.Theme.Data; using AtomUI.Theme.Styling; -using AtomUI.Utils; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; diff --git a/src/AtomUI.Controls/Calendar/BaseCalendarButton.cs b/src/AtomUI.Controls/Calendar/BaseCalendarButton.cs index ec5ab6c4e..439037c2e 100644 --- a/src/AtomUI.Controls/Calendar/BaseCalendarButton.cs +++ b/src/AtomUI.Controls/Calendar/BaseCalendarButton.cs @@ -1,6 +1,7 @@ using AtomUI.Controls.Utils; using AtomUI.Media; using AtomUI.Theme.Styling; +using Avalonia; using Avalonia.Animation; using Avalonia.Controls; using Avalonia.Controls.Metadata; @@ -17,6 +18,15 @@ namespace AtomUI.Controls; [PseudoClasses(StdPseudoClass.Selected, StdPseudoClass.InActive, BtnFocusedPC)] internal class BaseCalendarButton : AvaloniaButton { + internal static readonly StyledProperty IsMotionEnabledProperty + = AvaloniaProperty.Register(nameof(IsMotionEnabled), true); + + public bool IsMotionEnabled + { + get => GetValue(IsMotionEnabledProperty); + set => SetValue(IsMotionEnabledProperty, value); + } + private const string BtnFocusedPC = ":btnfocused"; /// @@ -103,11 +113,23 @@ internal class BaseCalendarButton : AvaloniaButton protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { SetPseudoClasses(); - Transitions ??= new Transitions + SetupTransitions(); + } + + private void SetupTransitions() + { + if (IsMotionEnabled) { - AnimationUtils.CreateTransition(BackgroundProperty, - SharedTokenKey.MotionDurationFast) - }; + Transitions ??= new Transitions + { + AnimationUtils.CreateTransition(BackgroundProperty, + SharedTokenKey.MotionDurationFast) + }; + } + else + { + Transitions = null; + } } /// @@ -187,4 +209,16 @@ internal class BaseCalendarButton : AvaloniaButton CalendarLeftMouseButtonUp?.Invoke(this, e); } } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (VisualRoot != null) + { + if (change.Property == IsMotionEnabledProperty) + { + SetupTransitions(); + } + } + } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/BaseCalendarDayButton.cs b/src/AtomUI.Controls/Calendar/BaseCalendarDayButton.cs index b3093f593..cabab683e 100644 --- a/src/AtomUI.Controls/Calendar/BaseCalendarDayButton.cs +++ b/src/AtomUI.Controls/Calendar/BaseCalendarDayButton.cs @@ -26,6 +26,15 @@ internal class BaseCalendarDayButton : AvaloniaButton internal const string TodayPC = ":today"; internal const string BlackoutPC = ":blackout"; internal const string DayfocusedPC = ":dayfocused"; + + internal static readonly StyledProperty IsMotionEnabledProperty + = AvaloniaProperty.Register(nameof(IsMotionEnabled), true); + + public bool IsMotionEnabled + { + get => GetValue(IsMotionEnabledProperty); + set => SetValue(IsMotionEnabledProperty, value); + } /// /// Default content for the CalendarDayButton. @@ -171,11 +180,23 @@ internal class BaseCalendarDayButton : AvaloniaButton protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { SetPseudoClasses(); - Transitions ??= new Transitions + SetupTransitions(); + } + + private void SetupTransitions() + { + if (IsMotionEnabled) { - AnimationUtils.CreateTransition(BackgroundProperty, - SharedTokenKey.MotionDurationFast) - }; + Transitions ??= new Transitions + { + AnimationUtils.CreateTransition(BackgroundProperty, + SharedTokenKey.MotionDurationFast) + }; + } + else + { + Transitions = null; + } } private void SetPseudoClasses() @@ -269,4 +290,16 @@ internal class BaseCalendarDayButton : AvaloniaButton SharedTokenKey.BorderThickness, BindingPriority.Template, new RenderScaleAwareThicknessConfigure(this)); } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (VisualRoot != null) + { + if (change.Property == IsMotionEnabledProperty) + { + SetupTransitions(); + } + } + } } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/BaseCalendarDayButtonTheme.cs b/src/AtomUI.Controls/Calendar/BaseCalendarDayButtonTheme.cs index 10a3a0ec0..b0c3bce76 100644 --- a/src/AtomUI.Controls/Calendar/BaseCalendarDayButtonTheme.cs +++ b/src/AtomUI.Controls/Calendar/BaseCalendarDayButtonTheme.cs @@ -8,7 +8,6 @@ using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Layout; -using Avalonia.Media; using Avalonia.Styling; namespace AtomUI.Controls; diff --git a/src/AtomUI.Controls/Calendar/Calendar.cs b/src/AtomUI.Controls/Calendar/Calendar.cs index dcb9298ff..0a0818be2 100644 --- a/src/AtomUI.Controls/Calendar/Calendar.cs +++ b/src/AtomUI.Controls/Calendar/Calendar.cs @@ -5,9 +5,10 @@ using System.Collections.ObjectModel; using System.Diagnostics; +using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; -using AtomUI.Utils; +using AtomUI.Theme.Utils; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; @@ -224,8 +225,383 @@ public class CalendarModeChangedEventArgs : RoutedEventArgs /// [TemplatePart(CalendarTheme.CalendarItemPart, typeof(CalendarItem))] [TemplatePart(CalendarTheme.RootPart, typeof(Panel))] -public class Calendar : TemplatedControl +public class Calendar : TemplatedControl, + IAnimationAwareControl, + IControlSharedTokenResourcesHost { + + #region 公共属性定义 + + public static readonly StyledProperty FirstDayOfWeekProperty = + AvaloniaProperty.Register( + nameof(FirstDayOfWeek), + DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek); + + public static readonly StyledProperty IsTodayHighlightedProperty = + AvaloniaProperty.Register( + nameof(IsTodayHighlighted), + true); + + public static readonly StyledProperty HeaderBackgroundProperty = + AvaloniaProperty.Register(nameof(HeaderBackground)); + + public static readonly StyledProperty DisplayModeProperty = + AvaloniaProperty.Register( + nameof(DisplayMode), + validate: IsValidDisplayMode); + + public static readonly StyledProperty SelectionModeProperty = + AvaloniaProperty.Register( + nameof(SelectionMode)); + + public static readonly StyledProperty SelectedDateProperty = + AvaloniaProperty.Register(nameof(SelectedDate), + defaultBindingMode: BindingMode.TwoWay); + + public static readonly StyledProperty DisplayDateProperty = + AvaloniaProperty.Register(nameof(DisplayDate), + defaultBindingMode: BindingMode.TwoWay); + + public static readonly StyledProperty DisplayDateStartProperty = + AvaloniaProperty.Register(nameof(DisplayDateStart), + defaultBindingMode: BindingMode.TwoWay); + + public static readonly StyledProperty DisplayDateEndProperty = + AvaloniaProperty.Register(nameof(DisplayDateEnd), + defaultBindingMode: BindingMode.TwoWay); + + public static readonly StyledProperty IsMotionEnabledProperty + = AvaloniaProperty.Register(nameof(IsMotionEnabled), true); + + public static readonly StyledProperty IsWaveAnimationEnabledProperty + = AvaloniaProperty.Register(nameof(IsWaveAnimationEnabled), true); + + /// + /// Gets or sets the day that is considered the beginning of the week. + /// + /// + /// A representing the beginning of + /// the week. The default is . + /// + public DayOfWeek FirstDayOfWeek + { + get => GetValue(FirstDayOfWeekProperty); + set => SetValue(FirstDayOfWeekProperty, value); + } + + /// + /// Gets or sets a value indicating whether the current date is + /// highlighted. + /// + /// + /// True if the current date is highlighted; otherwise, false. The + /// default is true. + /// + public bool IsTodayHighlighted + { + get => GetValue(IsTodayHighlightedProperty); + set => SetValue(IsTodayHighlightedProperty, value); + } + + public IBrush? HeaderBackground + { + get => GetValue(HeaderBackgroundProperty); + set => SetValue(HeaderBackgroundProperty, value); + } + + /// + /// Gets or sets a value indicating whether the calendar is displayed in + /// months, years, or decades. + /// + /// + /// A value indicating what length of time the + /// should display. + /// + public CalendarMode DisplayMode + { + get => GetValue(DisplayModeProperty); + set => SetValue(DisplayModeProperty, value); + } + + /// + /// Gets or sets a value that indicates what kind of selections are + /// allowed. + /// + /// + /// A value that indicates the current selection mode. The default is + /// . + /// + /// + /// + /// This property determines whether the Calendar allows no selection, + /// selection of a single date, or selection of multiple dates. The + /// selection mode is specified with the CalendarSelectionMode + /// enumeration. + /// + /// + /// When this property is changed, all selected dates will be cleared. + /// + /// + public CalendarSelectionMode SelectionMode + { + get => GetValue(SelectionModeProperty); + set => SetValue(SelectionModeProperty, value); + } + + /// + /// Gets or sets the currently selected date. + /// + /// The date currently selected. The default is null. + /// + /// The given date is outside the range specified by + /// + /// and + /// -or- + /// The given date is in the + /// + /// collection. + /// + /// + /// If set to anything other than null when + /// is + /// set to + /// . + /// + /// + /// Use this property when SelectionMode is set to SingleDate. In other + /// modes, this property will always be the first date in SelectedDates. + /// + public DateTime? SelectedDate + { + get => GetValue(SelectedDateProperty); + set => SetValue(SelectedDateProperty, value); + } + + /// + /// Gets or sets the date to display. + /// + /// The date to display. + /// + /// The given date is not in the range specified by + /// + /// and + /// . + /// + /// + /// + /// This property allows the developer to specify a date to display. If + /// this property is a null reference (Nothing in Visual Basic), + /// SelectedDate is displayed. If SelectedDate is also a null reference + /// (Nothing in Visual Basic), Today is displayed. The default is + /// Today. + /// + /// + /// To set this property in XAML, use a date specified in the format + /// yyyy/mm/dd. The mm and dd components must always consist of two + /// characters, with a leading zero if necessary. For instance, the + /// month of May should be specified as 05. + /// + /// + public DateTime DisplayDate + { + get => GetValue(DisplayDateProperty); + set => SetValue(DisplayDateProperty, value); + } + + /// + /// Gets a collection of selected dates. + /// + /// + /// A + /// object that contains the currently selected dates. The default is an + /// empty collection. + /// + /// + /// Dates can be added to the collection either individually or in a + /// range using the AddRange method. Depending on the value of the + /// SelectionMode property, adding a date or range to the collection may + /// cause it to be cleared. The following table lists how + /// CalendarSelectionMode affects the SelectedDates property. + /// CalendarSelectionMode Description + /// None No selections are allowed. SelectedDate + /// cannot be set and no values can be added + /// to SelectedDates. + /// SingleDate Only a single date can be selected, + /// either by setting SelectedDate or the + /// first value in SelectedDates. AddRange + /// cannot be used. + /// SingleRange A single range of dates can be selected. + /// Setting SelectedDate, adding a date + /// individually to SelectedDates, or using + /// AddRange will clear all previous values + /// from SelectedDates. + /// MultipleRange Multiple non-contiguous ranges of dates + /// can be selected. Adding a date + /// individually to SelectedDates or using + /// AddRange will not clear SelectedDates. + /// Setting SelectedDate will still clear + /// SelectedDates, but additional dates or + /// range can then be added. Adding a range + /// that includes some dates that are + /// already selected or overlaps with + /// another range results in the union of + /// the ranges and does not cause an + /// exception. + /// + public SelectedDatesCollection SelectedDates { get; } + + /// + /// Gets or sets the first date to be displayed. + /// + /// The first date to display. + /// + /// To set this property in XAML, use a date specified in the format + /// yyyy/mm/dd. The mm and dd components must always consist of two + /// characters, with a leading zero if necessary. For instance, the + /// month of May should be specified as 05. + /// + public DateTime? DisplayDateStart + { + get => GetValue(DisplayDateStartProperty); + set => SetValue(DisplayDateStartProperty, value); + } + + /// + /// Gets or sets the last date to be displayed. + /// + /// The last date to display. + /// + /// To set this property in XAML, use a date specified in the format + /// yyyy/mm/dd. The mm and dd components must always consist of two + /// characters, with a leading zero if necessary. For instance, the + /// month of May should be specified as 05. + /// + public DateTime? DisplayDateEnd + { + get => GetValue(DisplayDateEndProperty); + set => SetValue(DisplayDateEndProperty, value); + } + + public bool IsMotionEnabled + { + get => GetValue(IsMotionEnabledProperty); + set => SetValue(IsMotionEnabledProperty, value); + } + + public bool IsWaveAnimationEnabled + { + get => GetValue(IsWaveAnimationEnabledProperty); + set => SetValue(IsWaveAnimationEnabledProperty, value); + } + + #endregion + + #region 内部属性定义 + + internal CalendarDayButton? FocusButton { get; set; } + internal CalendarButton? FocusCalendarButton { get; set; } + + internal Panel? Root { get; set; } + + internal CalendarItem? MonthControl + { + get + { + if (Root != null && Root.Children.Count > 0) + { + return Root.Children[0] as CalendarItem; + } + + return null; + } + } + + internal Collection RemovedItems { get; set; } + internal DateTime? LastSelectedDateInternal { get; set; } + + internal DateTime? LastSelectedDate + { + get => LastSelectedDateInternal; + + set + { + LastSelectedDateInternal = value; + + if (SelectionMode == CalendarSelectionMode.None) + { + if (FocusButton != null) + { + FocusButton.IsCurrent = false; + } + + FocusButton = FindDayButtonFromDay(LastSelectedDate!.Value); + if (FocusButton != null) + { + FocusButton.IsCurrent = HasFocusInternal; + } + } + } + } + + internal DateTime SelectedMonth + { + get => _selectedMonth; + + set + { + var monthDifferenceStart = DateTimeHelper.CompareYearMonth(value, DisplayDateRangeStart); + var monthDifferenceEnd = DateTimeHelper.CompareYearMonth(value, DisplayDateRangeEnd); + + if (monthDifferenceStart >= 0 && monthDifferenceEnd <= 0) + { + _selectedMonth = DateTimeHelper.DiscardDayTime(value); + } + else + { + if (monthDifferenceStart < 0) + { + _selectedMonth = DateTimeHelper.DiscardDayTime(DisplayDateRangeStart); + } + else + { + Debug.Assert(monthDifferenceEnd > 0, "monthDifferenceEnd should be greater than 0!"); + _selectedMonth = DateTimeHelper.DiscardDayTime(DisplayDateRangeEnd); + } + } + } + } + + internal DateTime SelectedYear + { + get => _selectedYear; + + set + { + if (value.Year < DisplayDateRangeStart.Year) + { + _selectedYear = DisplayDateRangeStart; + } + else + { + if (value.Year > DisplayDateRangeEnd.Year) + { + _selectedYear = DisplayDateRangeEnd; + } + else + { + _selectedYear = value; + } + } + } + } + + internal DateTime DisplayDateInternal { get; set; } + Control IAnimationAwareControl.PropertyBindTarget => this; + Control IControlSharedTokenResourcesHost.HostControl => this; + string IControlSharedTokenResourcesHost.TokenId => CalendarToken.ID; + + #endregion + internal const int RowsPerMonth = 7; internal const int ColumnsPerMonth = 7; internal const int RowsPerYear = 3; @@ -260,6 +636,8 @@ public class Calendar : TemplatedControl /// public Calendar() { + this.RegisterResources(); + this.BindAnimationProperties(IsMotionEnabledProperty, IsWaveAnimationEnabledProperty); SetCurrentValue(DisplayDateProperty, DateTime.Today); UpdateDisplayDate(this, DisplayDate, DateTime.MinValue); BlackoutDates = new CalendarBlackoutDatesCollection(this); @@ -1873,355 +2251,5 @@ public class Calendar : TemplatedControl BindingPriority.Template, new RenderScaleAwareThicknessConfigure(this)); } - - #region 公共属性定义 - - public static readonly StyledProperty FirstDayOfWeekProperty = - AvaloniaProperty.Register( - nameof(FirstDayOfWeek), - DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek); - - /// - /// Gets or sets the day that is considered the beginning of the week. - /// - /// - /// A representing the beginning of - /// the week. The default is . - /// - public DayOfWeek FirstDayOfWeek - { - get => GetValue(FirstDayOfWeekProperty); - set => SetValue(FirstDayOfWeekProperty, value); - } - - public static readonly StyledProperty IsTodayHighlightedProperty = - AvaloniaProperty.Register( - nameof(IsTodayHighlighted), - true); - - /// - /// Gets or sets a value indicating whether the current date is - /// highlighted. - /// - /// - /// True if the current date is highlighted; otherwise, false. The - /// default is true. - /// - public bool IsTodayHighlighted - { - get => GetValue(IsTodayHighlightedProperty); - set => SetValue(IsTodayHighlightedProperty, value); - } - - public static readonly StyledProperty HeaderBackgroundProperty = - AvaloniaProperty.Register(nameof(HeaderBackground)); - - public IBrush? HeaderBackground - { - get => GetValue(HeaderBackgroundProperty); - set => SetValue(HeaderBackgroundProperty, value); - } - - public static readonly StyledProperty DisplayModeProperty = - AvaloniaProperty.Register( - nameof(DisplayMode), - validate: IsValidDisplayMode); - - /// - /// Gets or sets a value indicating whether the calendar is displayed in - /// months, years, or decades. - /// - /// - /// A value indicating what length of time the - /// should display. - /// - public CalendarMode DisplayMode - { - get => GetValue(DisplayModeProperty); - set => SetValue(DisplayModeProperty, value); - } - - public static readonly StyledProperty SelectionModeProperty = - AvaloniaProperty.Register( - nameof(SelectionMode)); - - /// - /// Gets or sets a value that indicates what kind of selections are - /// allowed. - /// - /// - /// A value that indicates the current selection mode. The default is - /// . - /// - /// - /// - /// This property determines whether the Calendar allows no selection, - /// selection of a single date, or selection of multiple dates. The - /// selection mode is specified with the CalendarSelectionMode - /// enumeration. - /// - /// - /// When this property is changed, all selected dates will be cleared. - /// - /// - public CalendarSelectionMode SelectionMode - { - get => GetValue(SelectionModeProperty); - set => SetValue(SelectionModeProperty, value); - } - - public static readonly StyledProperty SelectedDateProperty = - AvaloniaProperty.Register(nameof(SelectedDate), - defaultBindingMode: BindingMode.TwoWay); - - /// - /// Gets or sets the currently selected date. - /// - /// The date currently selected. The default is null. - /// - /// The given date is outside the range specified by - /// - /// and - /// -or- - /// The given date is in the - /// - /// collection. - /// - /// - /// If set to anything other than null when - /// is - /// set to - /// . - /// - /// - /// Use this property when SelectionMode is set to SingleDate. In other - /// modes, this property will always be the first date in SelectedDates. - /// - public DateTime? SelectedDate - { - get => GetValue(SelectedDateProperty); - set => SetValue(SelectedDateProperty, value); - } - - public static readonly StyledProperty DisplayDateProperty = - AvaloniaProperty.Register(nameof(DisplayDate), - defaultBindingMode: BindingMode.TwoWay); - - /// - /// Gets or sets the date to display. - /// - /// The date to display. - /// - /// The given date is not in the range specified by - /// - /// and - /// . - /// - /// - /// - /// This property allows the developer to specify a date to display. If - /// this property is a null reference (Nothing in Visual Basic), - /// SelectedDate is displayed. If SelectedDate is also a null reference - /// (Nothing in Visual Basic), Today is displayed. The default is - /// Today. - /// - /// - /// To set this property in XAML, use a date specified in the format - /// yyyy/mm/dd. The mm and dd components must always consist of two - /// characters, with a leading zero if necessary. For instance, the - /// month of May should be specified as 05. - /// - /// - public DateTime DisplayDate - { - get => GetValue(DisplayDateProperty); - set => SetValue(DisplayDateProperty, value); - } - - /// - /// Gets a collection of selected dates. - /// - /// - /// A - /// object that contains the currently selected dates. The default is an - /// empty collection. - /// - /// - /// Dates can be added to the collection either individually or in a - /// range using the AddRange method. Depending on the value of the - /// SelectionMode property, adding a date or range to the collection may - /// cause it to be cleared. The following table lists how - /// CalendarSelectionMode affects the SelectedDates property. - /// CalendarSelectionMode Description - /// None No selections are allowed. SelectedDate - /// cannot be set and no values can be added - /// to SelectedDates. - /// SingleDate Only a single date can be selected, - /// either by setting SelectedDate or the - /// first value in SelectedDates. AddRange - /// cannot be used. - /// SingleRange A single range of dates can be selected. - /// Setting SelectedDate, adding a date - /// individually to SelectedDates, or using - /// AddRange will clear all previous values - /// from SelectedDates. - /// MultipleRange Multiple non-contiguous ranges of dates - /// can be selected. Adding a date - /// individually to SelectedDates or using - /// AddRange will not clear SelectedDates. - /// Setting SelectedDate will still clear - /// SelectedDates, but additional dates or - /// range can then be added. Adding a range - /// that includes some dates that are - /// already selected or overlaps with - /// another range results in the union of - /// the ranges and does not cause an - /// exception. - /// - public SelectedDatesCollection SelectedDates { get; } - - public static readonly StyledProperty DisplayDateStartProperty = - AvaloniaProperty.Register(nameof(DisplayDateStart), - defaultBindingMode: BindingMode.TwoWay); - - /// - /// Gets or sets the first date to be displayed. - /// - /// The first date to display. - /// - /// To set this property in XAML, use a date specified in the format - /// yyyy/mm/dd. The mm and dd components must always consist of two - /// characters, with a leading zero if necessary. For instance, the - /// month of May should be specified as 05. - /// - public DateTime? DisplayDateStart - { - get => GetValue(DisplayDateStartProperty); - set => SetValue(DisplayDateStartProperty, value); - } - - public static readonly StyledProperty DisplayDateEndProperty = - AvaloniaProperty.Register(nameof(DisplayDateEnd), - defaultBindingMode: BindingMode.TwoWay); - - /// - /// Gets or sets the last date to be displayed. - /// - /// The last date to display. - /// - /// To set this property in XAML, use a date specified in the format - /// yyyy/mm/dd. The mm and dd components must always consist of two - /// characters, with a leading zero if necessary. For instance, the - /// month of May should be specified as 05. - /// - public DateTime? DisplayDateEnd - { - get => GetValue(DisplayDateEndProperty); - set => SetValue(DisplayDateEndProperty, value); - } - - #endregion - - #region 内部属性定义 - - internal CalendarDayButton? FocusButton { get; set; } - internal CalendarButton? FocusCalendarButton { get; set; } - - internal Panel? Root { get; set; } - - internal CalendarItem? MonthControl - { - get - { - if (Root != null && Root.Children.Count > 0) - { - return Root.Children[0] as CalendarItem; - } - - return null; - } - } - - internal Collection RemovedItems { get; set; } - internal DateTime? LastSelectedDateInternal { get; set; } - - internal DateTime? LastSelectedDate - { - get => LastSelectedDateInternal; - - set - { - LastSelectedDateInternal = value; - - if (SelectionMode == CalendarSelectionMode.None) - { - if (FocusButton != null) - { - FocusButton.IsCurrent = false; - } - - FocusButton = FindDayButtonFromDay(LastSelectedDate!.Value); - if (FocusButton != null) - { - FocusButton.IsCurrent = HasFocusInternal; - } - } - } - } - - internal DateTime SelectedMonth - { - get => _selectedMonth; - - set - { - var monthDifferenceStart = DateTimeHelper.CompareYearMonth(value, DisplayDateRangeStart); - var monthDifferenceEnd = DateTimeHelper.CompareYearMonth(value, DisplayDateRangeEnd); - - if (monthDifferenceStart >= 0 && monthDifferenceEnd <= 0) - { - _selectedMonth = DateTimeHelper.DiscardDayTime(value); - } - else - { - if (monthDifferenceStart < 0) - { - _selectedMonth = DateTimeHelper.DiscardDayTime(DisplayDateRangeStart); - } - else - { - Debug.Assert(monthDifferenceEnd > 0, "monthDifferenceEnd should be greater than 0!"); - _selectedMonth = DateTimeHelper.DiscardDayTime(DisplayDateRangeEnd); - } - } - } - } - - internal DateTime SelectedYear - { - get => _selectedYear; - - set - { - if (value.Year < DisplayDateRangeStart.Year) - { - _selectedYear = DisplayDateRangeStart; - } - else - { - if (value.Year > DisplayDateRangeEnd.Year) - { - _selectedYear = DisplayDateRangeEnd; - } - else - { - _selectedYear = value; - } - } - } - } - - internal DateTime DisplayDateInternal { get; set; } - - #endregion + } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/CalendarItem.cs b/src/AtomUI.Controls/Calendar/CalendarItem.cs index 3204db946..e59628713 100644 --- a/src/AtomUI.Controls/Calendar/CalendarItem.cs +++ b/src/AtomUI.Controls/Calendar/CalendarItem.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Globalization; using AtomUI.Collections.Pooled; +using AtomUI.Data; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Metadata; @@ -33,8 +34,8 @@ internal class CalendarItem : TemplatedControl internal const int NumberOfDaysPerWeek = 7; protected readonly System.Globalization.Calendar _calendar = new GregorianCalendar(); - - #region 公共属性定义 + + #region 公共属性定义 public static readonly StyledProperty HeaderBackgroundProperty = Calendar.HeaderBackgroundProperty.AddOwner(); @@ -271,6 +272,8 @@ internal class CalendarItem : TemplatedControl if (Owner != null) { cell.Owner = Owner; + BindUtils.RelayBind(Owner, Calendar.IsMotionEnabledProperty, cell, + BaseCalendarDayButton.IsMotionEnabledProperty); } cell.SetValue(Grid.RowProperty, i); @@ -303,6 +306,8 @@ internal class CalendarItem : TemplatedControl if (Owner != null) { + BindUtils.RelayBind(Owner, Calendar.IsMotionEnabledProperty, month, + BaseCalendarButton.IsMotionEnabledProperty); month.Owner = Owner; } @@ -337,6 +342,10 @@ internal class CalendarItem : TemplatedControl if (Owner != null) { UpdateDisabled(Owner.IsEnabled); + if (HeaderButton != null) + { + BindUtils.RelayBind(Owner, Calendar.IsMotionEnabledProperty, HeaderButton, HeadTextButton.IsMotionEnabledProperty); + } } PopulateGrids(); @@ -1309,5 +1318,4 @@ internal class CalendarItem : TemplatedControl { PseudoClasses.Set(CalendarDisabledPC, !isEnabled); } - } \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs b/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs index ee3c53c57..bc859fdec 100644 --- a/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs +++ b/src/AtomUI.Controls/Calendar/CalendarItemTheme.cs @@ -49,7 +49,7 @@ internal class CalendarItemTheme : BaseControlTheme Name = ItemRootLayoutPart, LastChildFill = true }; - BuildHeader(rootLayout, scope); + BuildHeader(calendarItem, rootLayout, scope); BuildContentView(rootLayout, scope); BuildDayTitleTemplate(calendarItem); @@ -64,7 +64,7 @@ internal class CalendarItemTheme : BaseControlTheme calendarItem.DayTitleTemplate = new DayTitleTemplate(); } - protected virtual void BuildHeader(DockPanel layout, INameScope scope) + protected virtual void BuildHeader(CalendarItem calendarItem, DockPanel layout, INameScope scope) { var headerLayout = new Grid { diff --git a/src/AtomUI.Controls/Calendar/CalendarWithTime.cs b/src/AtomUI.Controls/Calendar/CalendarWithTime.cs deleted file mode 100644 index 784c1f441..000000000 --- a/src/AtomUI.Controls/Calendar/CalendarWithTime.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace AtomUI.Controls; - -public class CalendarWithTime -{ -} \ No newline at end of file diff --git a/src/AtomUI.Controls/Calendar/HeadTextButton.cs b/src/AtomUI.Controls/Calendar/HeadTextButton.cs index 898f458b8..a923ab300 100644 --- a/src/AtomUI.Controls/Calendar/HeadTextButton.cs +++ b/src/AtomUI.Controls/Calendar/HeadTextButton.cs @@ -1,6 +1,7 @@ using AtomUI.Controls.Utils; using AtomUI.Media; using AtomUI.Theme.Styling; +using Avalonia; using Avalonia.Animation; using Avalonia.Controls.Primitives; @@ -10,13 +11,46 @@ using AvaloniaButton = Avalonia.Controls.Button; internal class HeadTextButton : AvaloniaButton { + internal static readonly StyledProperty IsMotionEnabledProperty + = AvaloniaProperty.Register(nameof(IsMotionEnabled), true); + + public bool IsMotionEnabled + { + get => GetValue(IsMotionEnabledProperty); + set => SetValue(IsMotionEnabledProperty, value); + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); - Transitions ??= new Transitions + SetupTransitions(); + } + + private void SetupTransitions() + { + if (IsMotionEnabled) { - AnimationUtils.CreateTransition(ForegroundProperty, - SharedTokenKey.MotionDurationFast) - }; + Transitions ??= new Transitions + { + AnimationUtils.CreateTransition(ForegroundProperty, + SharedTokenKey.MotionDurationFast) + }; + } + else + { + Transitions = null; + } + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (VisualRoot != null) + { + if (change.Property == IsMotionEnabledProperty) + { + SetupTransitions(); + } + } } } \ No newline at end of file