From 9318ce1612579cb5d1f7b36c33012137f955e9ac Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 7 Feb 2022 16:28:40 +0100 Subject: [PATCH 01/40] Added failing tests for #7552. --- .../LayoutableTests.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs b/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs index a8aa0bbf0e..514eae12c0 100644 --- a/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs +++ b/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs @@ -320,6 +320,71 @@ namespace Avalonia.Layout.UnitTests Times.Once); } + [Fact] + public void Making_Control_Invisible_Should_Invalidate_Parent_Measure() + { + Border child; + var target = new StackPanel + { + Children = + { + (child = new Border + { + Width = 100, + }), + } + }; + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(target.DesiredSize)); + + Assert.True(target.IsMeasureValid); + Assert.True(target.IsArrangeValid); + Assert.True(child.IsMeasureValid); + Assert.True(child.IsArrangeValid); + + child.IsVisible = false; + + Assert.False(target.IsMeasureValid); + Assert.False(target.IsArrangeValid); + Assert.True(child.IsMeasureValid); + Assert.True(child.IsArrangeValid); + } + + [Fact] + public void Measuring_Invisible_Control_Should_Not_Invalidate_Parent_Measure() + { + Border child; + var target = new StackPanel + { + Children = + { + (child = new Border + { + Width = 100, + }), + } + }; + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(target.DesiredSize)); + + Assert.True(target.IsMeasureValid); + Assert.True(target.IsArrangeValid); + Assert.Equal(new Size(100, 0), child.DesiredSize); + + child.IsVisible = false; + Assert.Equal(default, child.DesiredSize); + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(target.DesiredSize)); + child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + Assert.True(target.IsMeasureValid); + Assert.True(target.IsArrangeValid); + Assert.Equal(default, child.DesiredSize); + } + private class TestLayoutable : Layoutable { public Size ArrangeSize { get; private set; } From 1f3cb4fa00dfc6e443d92a1658517653c039066b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 7 Feb 2022 16:29:39 +0100 Subject: [PATCH 02/40] Invalidate parent measure when child visibility changes. Fixes #7552 but breaks `ListBoxTests.LayoutManager_Should_Measure_Arrange_All`. --- src/Avalonia.Layout/Layoutable.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Layout/Layoutable.cs b/src/Avalonia.Layout/Layoutable.cs index 09e0c4263a..516a70c3c9 100644 --- a/src/Avalonia.Layout/Layoutable.cs +++ b/src/Avalonia.Layout/Layoutable.cs @@ -141,7 +141,6 @@ namespace Avalonia.Layout static Layoutable() { AffectsMeasure( - IsVisibleProperty, WidthProperty, HeightProperty, MinWidthProperty, @@ -781,6 +780,17 @@ namespace Avalonia.Layout { } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == IsVisibleProperty) + { + DesiredSize = default; + this.GetVisualParent()?.ChildDesiredSizeChanged(this); + } + } + /// protected sealed override void OnVisualParentChanged(IVisual? oldParent, IVisual? newParent) { From 6624380456d65cd63569e108d313ac233a15956b Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 11:37:59 -0400 Subject: [PATCH 03/40] Update property definitions to latest conventions --- .../Calendar/CalendarDatePicker.cs | 130 ++++++++++++++---- 1 file changed, 103 insertions(+), 27 deletions(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 0ac2056ed1..09330c2304 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -160,32 +160,57 @@ namespace Avalonia.Controls /// public CalendarBlackoutDatesCollection? BlackoutDates { get; private set; } + /// + /// Defines the property. + /// public static readonly DirectProperty DisplayDateProperty = AvaloniaProperty.RegisterDirect( nameof(DisplayDate), o => o.DisplayDate, (o, v) => o.DisplayDate = v); + + /// + /// Defines the property. + /// public static readonly DirectProperty DisplayDateStartProperty = AvaloniaProperty.RegisterDirect( nameof(DisplayDateStart), o => o.DisplayDateStart, (o, v) => o.DisplayDateStart = v); + + /// + /// Defines the property. + /// public static readonly DirectProperty DisplayDateEndProperty = AvaloniaProperty.RegisterDirect( nameof(DisplayDateEnd), o => o.DisplayDateEnd, (o, v) => o.DisplayDateEnd = v); + + /// + /// Defines the property. + /// public static readonly StyledProperty FirstDayOfWeekProperty = AvaloniaProperty.Register(nameof(FirstDayOfWeek)); + /// + /// Defines the property. + /// public static readonly DirectProperty IsDropDownOpenProperty = AvaloniaProperty.RegisterDirect( nameof(IsDropDownOpen), o => o.IsDropDownOpen, (o, v) => o.IsDropDownOpen = v); + /// + /// Defines the property. + /// public static readonly StyledProperty IsTodayHighlightedProperty = AvaloniaProperty.Register(nameof(IsTodayHighlighted)); + + /// + /// Defines the property. + /// public static readonly DirectProperty SelectedDateProperty = AvaloniaProperty.RegisterDirect( nameof(SelectedDate), @@ -194,29 +219,45 @@ namespace Avalonia.Controls enableDataValidation: true, defaultBindingMode:BindingMode.TwoWay); + /// + /// Defines the property. + /// public static readonly StyledProperty SelectedDateFormatProperty = AvaloniaProperty.Register( nameof(SelectedDateFormat), defaultValue: CalendarDatePickerFormat.Short, validate: IsValidSelectedDateFormat); + /// + /// Defines the property. + /// public static readonly StyledProperty CustomDateFormatStringProperty = AvaloniaProperty.Register( nameof(CustomDateFormatString), defaultValue: "d", validate: IsValidDateFormatString); + /// + /// Defines the property. + /// public static readonly DirectProperty TextProperty = AvaloniaProperty.RegisterDirect( nameof(Text), o => o.Text, (o, v) => o.Text = v); + + /// + /// Defines the property. + /// public static readonly StyledProperty WatermarkProperty = TextBox.WatermarkProperty.AddOwner(); + + /// + /// Defines the property. + /// public static readonly StyledProperty UseFloatingWatermarkProperty = TextBox.UseFloatingWatermarkProperty.AddOwner(); - /// /// Defines the property. /// @@ -244,8 +285,8 @@ namespace Avalonia.Controls /// public DateTime DisplayDate { - get { return _displayDate; } - set { SetAndRaise(DisplayDateProperty, ref _displayDate, value); } + get => _displayDate; + set => SetAndRaise(DisplayDateProperty, ref _displayDate, value); } /// @@ -254,8 +295,8 @@ namespace Avalonia.Controls /// The first date to display. public DateTime? DisplayDateStart { - get { return _displayDateStart; } - set { SetAndRaise(DisplayDateStartProperty, ref _displayDateStart, value); } + get => _displayDateStart; + set => SetAndRaise(DisplayDateStartProperty, ref _displayDateStart, value); } /// @@ -264,8 +305,8 @@ namespace Avalonia.Controls /// The last date to display. public DateTime? DisplayDateEnd { - get { return _displayDateEnd; } - set { SetAndRaise(DisplayDateEndProperty, ref _displayDateEnd, value); } + get => _displayDateEnd; + set => SetAndRaise(DisplayDateEndProperty, ref _displayDateEnd, value); } /// @@ -277,8 +318,8 @@ namespace Avalonia.Controls /// public DayOfWeek FirstDayOfWeek { - get { return GetValue(FirstDayOfWeekProperty); } - set { SetValue(FirstDayOfWeekProperty, value); } + get => GetValue(FirstDayOfWeekProperty); + set => SetValue(FirstDayOfWeekProperty, value); } /// @@ -291,8 +332,8 @@ namespace Avalonia.Controls /// public bool IsDropDownOpen { - get { return _isDropDownOpen; } - set { SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); } + get => _isDropDownOpen; + set => SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); } /// @@ -305,8 +346,8 @@ namespace Avalonia.Controls /// public bool IsTodayHighlighted { - get { return GetValue(IsTodayHighlightedProperty); } - set { SetValue(IsTodayHighlightedProperty, value); } + get => GetValue(IsTodayHighlightedProperty); + set => SetValue(IsTodayHighlightedProperty, value); } /// @@ -326,8 +367,8 @@ namespace Avalonia.Controls /// public DateTime? SelectedDate { - get { return _selectedDate; } - set { SetAndRaise(SelectedDateProperty, ref _selectedDate, value); } + get => _selectedDate; + set => SetAndRaise(SelectedDateProperty, ref _selectedDate, value); } /// @@ -342,14 +383,14 @@ namespace Avalonia.Controls /// public CalendarDatePickerFormat SelectedDateFormat { - get { return GetValue(SelectedDateFormatProperty); } - set { SetValue(SelectedDateFormatProperty, value); } + get => GetValue(SelectedDateFormatProperty); + set => SetValue(SelectedDateFormatProperty, value); } public string CustomDateFormatString { - get { return GetValue(CustomDateFormatStringProperty); } - set { SetValue(CustomDateFormatStringProperty, value); } + get => GetValue(CustomDateFormatStringProperty); + set => SetValue(CustomDateFormatStringProperty, value); } /// @@ -369,22 +410,24 @@ namespace Avalonia.Controls /// public string? Text { - get { return _text; } - set { SetAndRaise(TextProperty, ref _text, value); } + get => _text; + set => SetAndRaise(TextProperty, ref _text, value); } + /// public string? Watermark { - get { return GetValue(WatermarkProperty); } - set { SetValue(WatermarkProperty, value); } + get => GetValue(WatermarkProperty); + set => SetValue(WatermarkProperty, value); } + + /// public bool UseFloatingWatermark { - get { return GetValue(UseFloatingWatermarkProperty); } - set { SetValue(UseFloatingWatermarkProperty, value); } + get => GetValue(UseFloatingWatermarkProperty); + set => SetValue(UseFloatingWatermarkProperty, value); } - /// /// Gets or sets the horizontal alignment of the content within the control. /// @@ -438,6 +481,7 @@ namespace Avalonia.Controls CustomDateFormatStringProperty.Changed.AddClassHandler((x,e) => x.OnCustomDateFormatStringChanged(e)); TextProperty.Changed.AddClassHandler((x,e) => x.OnTextChanged(e)); } + /// /// Initializes a new instance of the /// class. @@ -449,6 +493,7 @@ namespace Avalonia.Controls DisplayDate = DateTime.Today; } + /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { if (_calendar != null) @@ -562,6 +607,7 @@ namespace Avalonia.Controls } } } + protected override void OnGotFocus(GotFocusEventArgs e) { base.OnGotFocus(e); @@ -576,6 +622,7 @@ namespace Avalonia.Controls } } } + protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e); @@ -609,6 +656,7 @@ namespace Avalonia.Controls } } } + private void OnSelectedDateChanged(AvaloniaPropertyChangedEventArgs e) { var addedDate = (DateTime?)e.NewValue; @@ -648,6 +696,7 @@ namespace Avalonia.Controls OnDateSelected(addedDate, removedDate); } } + private void OnDateFormatChanged() { if (_textBox != null) @@ -672,10 +721,12 @@ namespace Avalonia.Controls } } } + private void OnSelectedDateFormatChanged(AvaloniaPropertyChangedEventArgs e) { OnDateFormatChanged(); } + private void OnCustomDateFormatStringChanged(AvaloniaPropertyChangedEventArgs e) { if(SelectedDateFormat == CalendarDatePickerFormat.Custom) @@ -683,6 +734,7 @@ namespace Avalonia.Controls OnDateFormatChanged(); } } + private void OnTextChanged(AvaloniaPropertyChangedEventArgs e) { var oldValue = (string?)e.OldValue; @@ -735,6 +787,7 @@ namespace Avalonia.Controls { DateValidationError?.Invoke(this, e); } + private void OnDateSelected(DateTime? addedDate, DateTime? removedDate) { EventHandler? handler = this.SelectedDateChanged; @@ -756,10 +809,12 @@ namespace Avalonia.Controls handler(this, new SelectionChangedEventArgs(SelectingItemsControl.SelectionChangedEvent, removedItems, addedItems)); } } + private void OnCalendarClosed(EventArgs e) { CalendarClosed?.Invoke(this, e); } + private void OnCalendarOpened(EventArgs e) { CalendarOpened?.Invoke(this, e); @@ -769,7 +824,8 @@ namespace Avalonia.Controls { Focus(); IsDropDownOpen = false; - } + } + private void Calendar_DisplayDateChanged(object? sender, CalendarDateChangedEventArgs e) { if (e.AddedDate != this.DisplayDate) @@ -777,6 +833,7 @@ namespace Avalonia.Controls SetValue(DisplayDateProperty, (DateTime) e.AddedDate!); } } + private void Calendar_SelectedDatesChanged(object? sender, SelectionChangedEventArgs e) { Debug.Assert(e.AddedItems.Count < 2, "There should be less than 2 AddedItems!"); @@ -802,6 +859,7 @@ namespace Avalonia.Controls } } } + private void Calendar_PointerReleased(object? sender, PointerReleasedEventArgs e) { @@ -810,6 +868,7 @@ namespace Avalonia.Controls e.Handled = true; } } + private void Calendar_KeyDown(object? sender, KeyEventArgs e) { Calendar? c = sender as Calendar ?? throw new ArgumentException("Sender must be Calendar.", nameof(sender)); @@ -825,10 +884,12 @@ namespace Avalonia.Controls } } } + private void TextBox_GotFocus(object? sender, RoutedEventArgs e) { IsDropDownOpen = false; } + private void TextBox_KeyDown(object? sender, KeyEventArgs e) { if (!e.Handled) @@ -836,6 +897,7 @@ namespace Avalonia.Controls e.Handled = ProcessDatePickerKey(e); } } + private void TextBox_TextChanged() { if (_textBox != null) @@ -845,10 +907,12 @@ namespace Avalonia.Controls _suspendTextChangeHandler = false; } } + private void DropDownButton_PointerPressed(object? sender, PointerPressedEventArgs e) { _ignoreButtonClick = _isPopupClosing; } + private void DropDownButton_Click(object? sender, RoutedEventArgs e) { if (!_ignoreButtonClick) @@ -860,6 +924,7 @@ namespace Avalonia.Controls _ignoreButtonClick = false; } } + private void PopUp_Closed(object? sender, EventArgs e) { IsDropDownOpen = false; @@ -883,6 +948,7 @@ namespace Avalonia.Controls ProcessTextBox(); } } + private void OpenDropDown() { if (_calendar != null) @@ -893,6 +959,7 @@ namespace Avalonia.Controls OnCalendarOpened(new RoutedEventArgs()); } } + private void OpenPopUp() { _onOpenSelectedDate = SelectedDate; @@ -946,6 +1013,7 @@ namespace Avalonia.Controls } return null; } + private string? DateTimeToString(DateTime d) { DateTimeFormatInfo dtfi = DateTimeHelper.GetCurrentDateFormat(); @@ -961,6 +1029,7 @@ namespace Avalonia.Controls } return null; } + private bool ProcessDatePickerKey(KeyEventArgs e) { @@ -983,12 +1052,14 @@ namespace Avalonia.Controls } return false; } + private void ProcessTextBox() { SetSelectedDate(); IsDropDownOpen = true; _calendar!.Focus(); } + private void SetSelectedDate() { if (_textBox != null) @@ -1037,6 +1108,7 @@ namespace Avalonia.Controls } } } + private DateTime? SetTextBoxValue(string s) { if (string.IsNullOrEmpty(s)) @@ -1070,6 +1142,7 @@ namespace Avalonia.Controls } } } + private void SetWaterMarkText() { if (_textBox != null) @@ -1111,10 +1184,12 @@ namespace Avalonia.Controls || value == CalendarDatePickerFormat.Short || value == CalendarDatePickerFormat.Custom; } + private static bool IsValidDateFormatString(string formatString) { return !string.IsNullOrWhiteSpace(formatString); } + private static DateTime DiscardDayTime(DateTime d) { int year = d.Year; @@ -1122,6 +1197,7 @@ namespace Avalonia.Controls DateTime newD = new DateTime(year, month, 1, 0, 0, 0); return newD; } + private static DateTime? DiscardTime(DateTime? d) { if (d == null) From 03cbe93d46550cc858fa99db53a4165636b33619 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 11:38:19 -0400 Subject: [PATCH 04/40] Update XAML formatting --- .../Controls/CalendarDatePicker.xaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index ffd3972b66..4e0c7082c7 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -82,7 +82,13 @@ FontSize="{DynamicResource CalendarDatePickerCurrentDayFontSize}" Text="{Binding Source={x:Static sys:DateTime.Today}, Path=Day}"/> - + From 94d2b467cd71077d5897ffdfa68d57db006371d2 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 11:42:26 -0400 Subject: [PATCH 05/40] Move CalendarDatePicker properties into partial class --- .../Calendar/CalendarDatePicker.Properties.cs | 306 ++++++++++++++++++ .../Calendar/CalendarDatePicker.cs | 297 +---------------- 2 files changed, 307 insertions(+), 296 deletions(-) create mode 100644 src/Avalonia.Controls/Calendar/CalendarDatePicker.Properties.cs diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.Properties.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.Properties.cs new file mode 100644 index 0000000000..e8fee4789b --- /dev/null +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.Properties.cs @@ -0,0 +1,306 @@ +using System; +using Avalonia.Controls.Primitives; +using Avalonia.Data; +using Avalonia.Layout; + +namespace Avalonia.Controls +{ + /// + public partial class CalendarDatePicker + { + /// + /// Defines the property. + /// + public static readonly DirectProperty DisplayDateProperty = + AvaloniaProperty.RegisterDirect( + nameof(DisplayDate), + o => o.DisplayDate, + (o, v) => o.DisplayDate = v); + + /// + /// Defines the property. + /// + public static readonly DirectProperty DisplayDateStartProperty = + AvaloniaProperty.RegisterDirect( + nameof(DisplayDateStart), + o => o.DisplayDateStart, + (o, v) => o.DisplayDateStart = v); + + /// + /// Defines the property. + /// + public static readonly DirectProperty DisplayDateEndProperty = + AvaloniaProperty.RegisterDirect( + nameof(DisplayDateEnd), + o => o.DisplayDateEnd, + (o, v) => o.DisplayDateEnd = v); + + /// + /// Defines the property. + /// + public static readonly StyledProperty FirstDayOfWeekProperty = + AvaloniaProperty.Register(nameof(FirstDayOfWeek)); + + /// + /// Defines the property. + /// + public static readonly DirectProperty IsDropDownOpenProperty = + AvaloniaProperty.RegisterDirect( + nameof(IsDropDownOpen), + o => o.IsDropDownOpen, + (o, v) => o.IsDropDownOpen = v); + + /// + /// Defines the property. + /// + public static readonly StyledProperty IsTodayHighlightedProperty = + AvaloniaProperty.Register(nameof(IsTodayHighlighted)); + + /// + /// Defines the property. + /// + public static readonly DirectProperty SelectedDateProperty = + AvaloniaProperty.RegisterDirect( + nameof(SelectedDate), + o => o.SelectedDate, + (o, v) => o.SelectedDate = v, + enableDataValidation: true, + defaultBindingMode:BindingMode.TwoWay); + + /// + /// Defines the property. + /// + public static readonly StyledProperty SelectedDateFormatProperty = + AvaloniaProperty.Register( + nameof(SelectedDateFormat), + defaultValue: CalendarDatePickerFormat.Short, + validate: IsValidSelectedDateFormat); + + /// + /// Defines the property. + /// + public static readonly StyledProperty CustomDateFormatStringProperty = + AvaloniaProperty.Register( + nameof(CustomDateFormatString), + defaultValue: "d", + validate: IsValidDateFormatString); + + /// + /// Defines the property. + /// + public static readonly DirectProperty TextProperty = + AvaloniaProperty.RegisterDirect( + nameof(Text), + o => o.Text, + (o, v) => o.Text = v); + + /// + /// Defines the property. + /// + public static readonly StyledProperty WatermarkProperty = + TextBox.WatermarkProperty.AddOwner(); + + /// + /// Defines the property. + /// + public static readonly StyledProperty UseFloatingWatermarkProperty = + TextBox.UseFloatingWatermarkProperty.AddOwner(); + + /// + /// Defines the property. + /// + public static readonly StyledProperty HorizontalContentAlignmentProperty = + ContentControl.HorizontalContentAlignmentProperty.AddOwner(); + + /// + /// Defines the property. + /// + public static readonly StyledProperty VerticalContentAlignmentProperty = + ContentControl.VerticalContentAlignmentProperty.AddOwner(); + + /// + /// Gets a collection of dates that are marked as not selectable. + /// + /// + /// A collection of dates that cannot be selected. The default value is + /// an empty collection. + /// + public CalendarBlackoutDatesCollection? BlackoutDates { get; private set; } + + /// + /// Gets or sets the date to display. + /// + /// + /// The date to display. The default + /// . + /// + /// + /// The specified date is not in the range defined by + /// + /// and + /// . + /// + public DateTime DisplayDate + { + get => _displayDate; + set => SetAndRaise(DisplayDateProperty, ref _displayDate, value); + } + + /// + /// Gets or sets the first date to be displayed. + /// + /// The first date to display. + public DateTime? DisplayDateStart + { + get => _displayDateStart; + set => SetAndRaise(DisplayDateStartProperty, ref _displayDateStart, value); + } + + /// + /// Gets or sets the last date to be displayed. + /// + /// The last date to display. + public DateTime? DisplayDateEnd + { + get => _displayDateEnd; + set => SetAndRaise(DisplayDateEndProperty, ref _displayDateEnd, value); + } + + /// + /// 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 drop-down + /// is open or closed. + /// + /// + /// True if the is + /// open; otherwise, false. The default is false. + /// + public bool IsDropDownOpen + { + get => _isDropDownOpen; + set => SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); + } + + /// + /// Gets or sets a value indicating whether the current date will be + /// highlighted. + /// + /// + /// True if the current date is highlighted; otherwise, false. The + /// default is true. + /// + public bool IsTodayHighlighted + { + get => GetValue(IsTodayHighlightedProperty); + set => SetValue(IsTodayHighlightedProperty, value); + } + + /// + /// Gets or sets the currently selected date. + /// + /// + /// The date currently selected. The default is null. + /// + /// + /// The specified date is not in the range defined by + /// + /// and + /// , + /// or the specified date is in the + /// + /// collection. + /// + public DateTime? SelectedDate + { + get => _selectedDate; + set => SetAndRaise(SelectedDateProperty, ref _selectedDate, value); + } + + /// + /// Gets or sets the format that is used to display the selected date. + /// + /// + /// The format that is used to display the selected date. The default is + /// . + /// + /// + /// An specified format is not valid. + /// + public CalendarDatePickerFormat SelectedDateFormat + { + get => GetValue(SelectedDateFormatProperty); + set => SetValue(SelectedDateFormatProperty, value); + } + + public string CustomDateFormatString + { + get => GetValue(CustomDateFormatStringProperty); + set => SetValue(CustomDateFormatStringProperty, value); + } + + /// + /// Gets or sets the text that is displayed by the + /// . + /// + /// + /// The text displayed by the + /// . + /// + /// + /// The text entered cannot be parsed to a valid date, and the exception + /// is not suppressed. + /// + /// + /// The text entered parses to a date that is not selectable. + /// + public string? Text + { + get => _text; + set => SetAndRaise(TextProperty, ref _text, value); + } + + /// + public string? Watermark + { + get => GetValue(WatermarkProperty); + set => SetValue(WatermarkProperty, value); + } + + /// + public bool UseFloatingWatermark + { + get => GetValue(UseFloatingWatermarkProperty); + set => SetValue(UseFloatingWatermarkProperty, value); + } + + /// + /// Gets or sets the horizontal alignment of the content within the control. + /// + public HorizontalAlignment HorizontalContentAlignment + { + get => GetValue(HorizontalContentAlignmentProperty); + set => SetValue(HorizontalContentAlignmentProperty, value); + } + + /// + /// Gets or sets the vertical alignment of the content within the control. + /// + public VerticalAlignment VerticalContentAlignment + { + get => GetValue(VerticalContentAlignmentProperty); + set => SetValue(VerticalContentAlignmentProperty, value); + } + } +} diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 09330c2304..55ecd6b50c 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -121,7 +121,7 @@ namespace Avalonia.Controls [TemplatePart(ElementCalendar, typeof(Calendar))] [TemplatePart(ElementPopup, typeof(Popup))] [TemplatePart(ElementTextBox, typeof(TextBox))] - public class CalendarDatePicker : TemplatedControl + public partial class CalendarDatePicker : TemplatedControl { private const string ElementTextBox = "PART_TextBox"; private const string ElementButton = "PART_Button"; @@ -151,301 +151,6 @@ namespace Avalonia.Controls private bool _isPopupClosing = false; private bool _ignoreButtonClick = false; - /// - /// Gets a collection of dates that are marked as not selectable. - /// - /// - /// A collection of dates that cannot be selected. The default value is - /// an empty collection. - /// - public CalendarBlackoutDatesCollection? BlackoutDates { get; private set; } - - /// - /// Defines the property. - /// - public static readonly DirectProperty DisplayDateProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDate), - o => o.DisplayDate, - (o, v) => o.DisplayDate = v); - - /// - /// Defines the property. - /// - public static readonly DirectProperty DisplayDateStartProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDateStart), - o => o.DisplayDateStart, - (o, v) => o.DisplayDateStart = v); - - /// - /// Defines the property. - /// - public static readonly DirectProperty DisplayDateEndProperty = - AvaloniaProperty.RegisterDirect( - nameof(DisplayDateEnd), - o => o.DisplayDateEnd, - (o, v) => o.DisplayDateEnd = v); - - /// - /// Defines the property. - /// - public static readonly StyledProperty FirstDayOfWeekProperty = - AvaloniaProperty.Register(nameof(FirstDayOfWeek)); - - /// - /// Defines the property. - /// - public static readonly DirectProperty IsDropDownOpenProperty = - AvaloniaProperty.RegisterDirect( - nameof(IsDropDownOpen), - o => o.IsDropDownOpen, - (o, v) => o.IsDropDownOpen = v); - - /// - /// Defines the property. - /// - public static readonly StyledProperty IsTodayHighlightedProperty = - AvaloniaProperty.Register(nameof(IsTodayHighlighted)); - - /// - /// Defines the property. - /// - public static readonly DirectProperty SelectedDateProperty = - AvaloniaProperty.RegisterDirect( - nameof(SelectedDate), - o => o.SelectedDate, - (o, v) => o.SelectedDate = v, - enableDataValidation: true, - defaultBindingMode:BindingMode.TwoWay); - - /// - /// Defines the property. - /// - public static readonly StyledProperty SelectedDateFormatProperty = - AvaloniaProperty.Register( - nameof(SelectedDateFormat), - defaultValue: CalendarDatePickerFormat.Short, - validate: IsValidSelectedDateFormat); - - /// - /// Defines the property. - /// - public static readonly StyledProperty CustomDateFormatStringProperty = - AvaloniaProperty.Register( - nameof(CustomDateFormatString), - defaultValue: "d", - validate: IsValidDateFormatString); - - /// - /// Defines the property. - /// - public static readonly DirectProperty TextProperty = - AvaloniaProperty.RegisterDirect( - nameof(Text), - o => o.Text, - (o, v) => o.Text = v); - - /// - /// Defines the property. - /// - public static readonly StyledProperty WatermarkProperty = - TextBox.WatermarkProperty.AddOwner(); - - /// - /// Defines the property. - /// - public static readonly StyledProperty UseFloatingWatermarkProperty = - TextBox.UseFloatingWatermarkProperty.AddOwner(); - - /// - /// Defines the property. - /// - public static readonly StyledProperty HorizontalContentAlignmentProperty = - ContentControl.HorizontalContentAlignmentProperty.AddOwner(); - - /// - /// Defines the property. - /// - public static readonly StyledProperty VerticalContentAlignmentProperty = - ContentControl.VerticalContentAlignmentProperty.AddOwner(); - - /// - /// Gets or sets the date to display. - /// - /// - /// The date to display. The default - /// . - /// - /// - /// The specified date is not in the range defined by - /// - /// and - /// . - /// - public DateTime DisplayDate - { - get => _displayDate; - set => SetAndRaise(DisplayDateProperty, ref _displayDate, value); - } - - /// - /// Gets or sets the first date to be displayed. - /// - /// The first date to display. - public DateTime? DisplayDateStart - { - get => _displayDateStart; - set => SetAndRaise(DisplayDateStartProperty, ref _displayDateStart, value); - } - - /// - /// Gets or sets the last date to be displayed. - /// - /// The last date to display. - public DateTime? DisplayDateEnd - { - get => _displayDateEnd; - set => SetAndRaise(DisplayDateEndProperty, ref _displayDateEnd, value); - } - - /// - /// 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 drop-down - /// is open or closed. - /// - /// - /// True if the is - /// open; otherwise, false. The default is false. - /// - public bool IsDropDownOpen - { - get => _isDropDownOpen; - set => SetAndRaise(IsDropDownOpenProperty, ref _isDropDownOpen, value); - } - - /// - /// Gets or sets a value indicating whether the current date will be - /// highlighted. - /// - /// - /// True if the current date is highlighted; otherwise, false. The - /// default is true. - /// - public bool IsTodayHighlighted - { - get => GetValue(IsTodayHighlightedProperty); - set => SetValue(IsTodayHighlightedProperty, value); - } - - /// - /// Gets or sets the currently selected date. - /// - /// - /// The date currently selected. The default is null. - /// - /// - /// The specified date is not in the range defined by - /// - /// and - /// , - /// or the specified date is in the - /// - /// collection. - /// - public DateTime? SelectedDate - { - get => _selectedDate; - set => SetAndRaise(SelectedDateProperty, ref _selectedDate, value); - } - - /// - /// Gets or sets the format that is used to display the selected date. - /// - /// - /// The format that is used to display the selected date. The default is - /// . - /// - /// - /// An specified format is not valid. - /// - public CalendarDatePickerFormat SelectedDateFormat - { - get => GetValue(SelectedDateFormatProperty); - set => SetValue(SelectedDateFormatProperty, value); - } - - public string CustomDateFormatString - { - get => GetValue(CustomDateFormatStringProperty); - set => SetValue(CustomDateFormatStringProperty, value); - } - - /// - /// Gets or sets the text that is displayed by the - /// . - /// - /// - /// The text displayed by the - /// . - /// - /// - /// The text entered cannot be parsed to a valid date, and the exception - /// is not suppressed. - /// - /// - /// The text entered parses to a date that is not selectable. - /// - public string? Text - { - get => _text; - set => SetAndRaise(TextProperty, ref _text, value); - } - - /// - public string? Watermark - { - get => GetValue(WatermarkProperty); - set => SetValue(WatermarkProperty, value); - } - - /// - public bool UseFloatingWatermark - { - get => GetValue(UseFloatingWatermarkProperty); - set => SetValue(UseFloatingWatermarkProperty, value); - } - - /// - /// Gets or sets the horizontal alignment of the content within the control. - /// - public HorizontalAlignment HorizontalContentAlignment - { - get => GetValue(HorizontalContentAlignmentProperty); - set => SetValue(HorizontalContentAlignmentProperty, value); - } - - /// - /// Gets or sets the vertical alignment of the content within the control. - /// - public VerticalAlignment VerticalContentAlignment - { - get => GetValue(VerticalContentAlignmentProperty); - set => SetValue(VerticalContentAlignmentProperty, value); - } - /// /// Occurs when the drop-down /// is closed. From 41246473bb0fb22cf9d932a90248bc750c49ffb6 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 11:47:45 -0400 Subject: [PATCH 06/40] Use OnPropertyChanged overridable method --- .../Calendar/CalendarDatePicker.cs | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 55ecd6b50c..8551205b78 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -179,12 +179,6 @@ namespace Avalonia.Controls static CalendarDatePicker() { FocusableProperty.OverrideDefaultValue(true); - - IsDropDownOpenProperty.Changed.AddClassHandler((x,e) => x.OnIsDropDownOpenChanged(e)); - SelectedDateProperty.Changed.AddClassHandler((x,e) => x.OnSelectedDateChanged(e)); - SelectedDateFormatProperty.Changed.AddClassHandler((x,e) => x.OnSelectedDateFormatChanged(e)); - CustomDateFormatStringProperty.Changed.AddClassHandler((x,e) => x.OnCustomDateFormatStringChanged(e)); - TextProperty.Changed.AddClassHandler((x,e) => x.OnTextChanged(e)); } /// @@ -290,6 +284,33 @@ namespace Avalonia.Controls } } + /// + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + if (change.Property == CustomDateFormatStringProperty) + { + OnCustomDateFormatStringChanged(change); + } + else if (change.Property == IsDropDownOpenProperty) + { + OnIsDropDownOpenChanged(change); + } + else if (change.Property == SelectedDateProperty) + { + OnSelectedDateChanged(change); + } + else if (change.Property == SelectedDateFormatProperty) + { + OnSelectedDateFormatChanged(change); + } + else if (change.Property == TextProperty) + { + OnTextChanged(change); + } + + base.OnPropertyChanged(change); + } + protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value) { if (property == SelectedDateProperty) From 312edcbb4c9aec76316d4c36b8e15d35f87f27cf Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 12:04:31 -0400 Subject: [PATCH 07/40] Remove single-use methods and process within OnPropertyChanged --- .../Calendar/CalendarDatePicker.cs | 230 ++++++++---------- 1 file changed, 107 insertions(+), 123 deletions(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 8551205b78..9e703b40a9 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -287,25 +287,124 @@ namespace Avalonia.Controls /// protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { + // CustomDateFormatString if (change.Property == CustomDateFormatStringProperty) { - OnCustomDateFormatStringChanged(change); + if (SelectedDateFormat == CalendarDatePickerFormat.Custom) + { + OnDateFormatChanged(); + } } + // IsDropDownOpen else if (change.Property == IsDropDownOpenProperty) { - OnIsDropDownOpenChanged(change); + var oldValue = change.OldValue.GetValueOrDefault(); + var value = change.NewValue.GetValueOrDefault(); + + if (_popUp != null && _popUp.Child != null) + { + if (value != oldValue) + { + if (_calendar!.DisplayMode != CalendarMode.Month) + { + _calendar.DisplayMode = CalendarMode.Month; + } + + if (value) + { + OpenDropDown(); + } + else + { + _popUp.IsOpen = false; + OnCalendarClosed(new RoutedEventArgs()); + } + } + } } + // SelectedDate else if (change.Property == SelectedDateProperty) { - OnSelectedDateChanged(change); + var addedDate = change.NewValue.GetValueOrDefault() as DateTime?; + var removedDate = change.OldValue.GetValueOrDefault() as DateTime?; + + if (SelectedDate != null) + { + DateTime day = SelectedDate.Value; + + // When the SelectedDateProperty change is done from + // OnTextPropertyChanged method, two-way binding breaks if + // BeginInvoke is not used: + Threading.Dispatcher.UIThread.InvokeAsync(() => + { + _settingSelectedDate = true; + Text = DateTimeToString(day); + _settingSelectedDate = false; + OnDateSelected(addedDate, removedDate); + }); + + // When DatePickerDisplayDateFlag is TRUE, the SelectedDate + // change is coming from the Calendar UI itself, so, we + // shouldn't change the DisplayDate since it will automatically + // be changed by the Calendar + if ((day.Month != DisplayDate.Month || day.Year != DisplayDate.Year) && (_calendar == null || !_calendar.CalendarDatePickerDisplayDateFlag)) + { + DisplayDate = day; + } + if(_calendar != null) + _calendar.CalendarDatePickerDisplayDateFlag = false; + } + else + { + _settingSelectedDate = true; + SetWaterMarkText(); + _settingSelectedDate = false; + OnDateSelected(addedDate, removedDate); + } } + // SelectedDateFormat else if (change.Property == SelectedDateFormatProperty) { - OnSelectedDateFormatChanged(change); + OnDateFormatChanged(); } + // Text else if (change.Property == TextProperty) { - OnTextChanged(change); + var oldValue = change.OldValue.GetValueOrDefault() as string; + var value = change.NewValue.GetValueOrDefault() as string; + + if (!_suspendTextChangeHandler) + { + if (value != null) + { + if (_textBox != null) + { + _textBox.Text = value; + } + else + { + _defaultText = value; + } + + if (!_settingSelectedDate) + { + SetSelectedDate(); + } + } + else + { + if (!_settingSelectedDate) + { + _settingSelectedDate = true; + SelectedDate = null; + _settingSelectedDate = false; + } + } + } + else + { + SetWaterMarkText(); + } } base.OnPropertyChanged(change); @@ -355,73 +454,6 @@ namespace Avalonia.Controls SetSelectedDate(); } - - private void OnIsDropDownOpenChanged(AvaloniaPropertyChangedEventArgs e) - { - var oldValue = (bool)e.OldValue!; - var value = (bool)e.NewValue!; - - if (_popUp != null && _popUp.Child != null) - { - if (value != oldValue) - { - if (_calendar!.DisplayMode != CalendarMode.Month) - { - _calendar.DisplayMode = CalendarMode.Month; - } - - if (value) - { - OpenDropDown(); - } - else - { - _popUp.IsOpen = false; - OnCalendarClosed(new RoutedEventArgs()); - } - } - } - } - - private void OnSelectedDateChanged(AvaloniaPropertyChangedEventArgs e) - { - var addedDate = (DateTime?)e.NewValue; - var removedDate = (DateTime?)e.OldValue; - - if (SelectedDate != null) - { - DateTime day = SelectedDate.Value; - - // When the SelectedDateProperty change is done from - // OnTextPropertyChanged method, two-way binding breaks if - // BeginInvoke is not used: - Threading.Dispatcher.UIThread.InvokeAsync(() => - { - _settingSelectedDate = true; - Text = DateTimeToString(day); - _settingSelectedDate = false; - OnDateSelected(addedDate, removedDate); - }); - - // When DatePickerDisplayDateFlag is TRUE, the SelectedDate - // change is coming from the Calendar UI itself, so, we - // shouldn't change the DisplayDate since it will automatically - // be changed by the Calendar - if ((day.Month != DisplayDate.Month || day.Year != DisplayDate.Year) && (_calendar == null || !_calendar.CalendarDatePickerDisplayDateFlag)) - { - DisplayDate = day; - } - if(_calendar != null) - _calendar.CalendarDatePickerDisplayDateFlag = false; - } - else - { - _settingSelectedDate = true; - SetWaterMarkText(); - _settingSelectedDate = false; - OnDateSelected(addedDate, removedDate); - } - } private void OnDateFormatChanged() { @@ -448,57 +480,6 @@ namespace Avalonia.Controls } } - private void OnSelectedDateFormatChanged(AvaloniaPropertyChangedEventArgs e) - { - OnDateFormatChanged(); - } - - private void OnCustomDateFormatStringChanged(AvaloniaPropertyChangedEventArgs e) - { - if(SelectedDateFormat == CalendarDatePickerFormat.Custom) - { - OnDateFormatChanged(); - } - } - - private void OnTextChanged(AvaloniaPropertyChangedEventArgs e) - { - var oldValue = (string?)e.OldValue; - var value = (string?)e.NewValue; - - if (!_suspendTextChangeHandler) - { - if (value != null) - { - if (_textBox != null) - { - _textBox.Text = value; - } - else - { - _defaultText = value; - } - if (!_settingSelectedDate) - { - SetSelectedDate(); - } - } - else - { - if (!_settingSelectedDate) - { - _settingSelectedDate = true; - SelectedDate = null; - _settingSelectedDate = false; - } - } - } - else - { - SetWaterMarkText(); - } - } - /// /// Raises the /// @@ -737,6 +718,7 @@ namespace Avalonia.Controls throw textParseError.Exception; } } + return null; } @@ -753,6 +735,7 @@ namespace Avalonia.Controls case CalendarDatePickerFormat.Custom: return string.Format(CultureInfo.CurrentCulture, d.ToString(CustomDateFormatString, dtfi)); } + return null; } @@ -776,6 +759,7 @@ namespace Avalonia.Controls break; } } + return false; } From ba7ccfbbb6523bd11b0470b25a4245a3579481c6 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 12:05:01 -0400 Subject: [PATCH 08/40] Remove unused methods --- .../Calendar/CalendarDatePicker.cs | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 9e703b40a9..775880f117 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -899,30 +899,5 @@ namespace Avalonia.Controls { return !string.IsNullOrWhiteSpace(formatString); } - - private static DateTime DiscardDayTime(DateTime d) - { - int year = d.Year; - int month = d.Month; - DateTime newD = new DateTime(year, month, 1, 0, 0, 0); - return newD; - } - - private static DateTime? DiscardTime(DateTime? d) - { - if (d == null) - { - return null; - } - else - { - DateTime discarded = (DateTime) d; - int year = discarded.Year; - int month = discarded.Month; - int day = discarded.Day; - DateTime newD = new DateTime(year, month, day, 0, 0, 0); - return newD; - } - } } } From d8685527136514ea260ec1ffeab042fc38fc15a8 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 12:06:53 -0400 Subject: [PATCH 09/40] Move CalendarDatePickerDateValidationErrorEventArgs into its own file --- .../Calendar/CalendarDatePicker.cs | 78 ------------------ ...rDatePickerDateValidationErrorEventArgs.cs | 82 +++++++++++++++++++ 2 files changed, 82 insertions(+), 78 deletions(-) create mode 100644 src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 775880f117..ddff1908c1 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -12,87 +12,9 @@ using Avalonia.Controls.Primitives; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; -using Avalonia.Layout; namespace Avalonia.Controls { - /// - /// Provides data for the - /// - /// event. - /// - public class CalendarDatePickerDateValidationErrorEventArgs : EventArgs - { - private bool _throwException; - - /// - /// Initializes a new instance of the - /// - /// class. - /// - /// - /// The initial exception from the - /// - /// event. - /// - /// - /// The text that caused the - /// - /// event. - /// - public CalendarDatePickerDateValidationErrorEventArgs(Exception exception, string text) - { - this.Text = text; - this.Exception = exception; - } - - /// - /// Gets the initial exception associated with the - /// - /// event. - /// - /// - /// The exception associated with the validation failure. - /// - public Exception Exception { get; private set; } - - /// - /// Gets the text that caused the - /// - /// event. - /// - /// - /// The text that caused the validation failure. - /// - public string Text { get; private set; } - - /// - /// Gets or sets a value indicating whether - /// - /// should be thrown. - /// - /// - /// True if the exception should be thrown; otherwise, false. - /// - /// - /// If set to true and - /// - /// is null. - /// - public bool ThrowException - { - get { return this._throwException; } - set - { - if (value && this.Exception == null) - { - throw new ArgumentException("Cannot Throw Null Exception"); - } - this._throwException = value; - } - } - } - /// /// Specifies date formats for a /// . diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs b/src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs new file mode 100644 index 0000000000..ba7c579461 --- /dev/null +++ b/src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs @@ -0,0 +1,82 @@ +using System; + +namespace Avalonia.Controls +{ + /// + /// Provides data for the + /// + /// event. + /// + public class CalendarDatePickerDateValidationErrorEventArgs : EventArgs + { + private bool _throwException; + + /// + /// Initializes a new instance of the + /// + /// class. + /// + /// + /// The initial exception from the + /// + /// event. + /// + /// + /// The text that caused the + /// + /// event. + /// + public CalendarDatePickerDateValidationErrorEventArgs(Exception exception, string text) + { + Text = text; + Exception = exception; + } + + /// + /// Gets the initial exception associated with the + /// + /// event. + /// + /// + /// The exception associated with the validation failure. + /// + public Exception Exception { get; private set; } + + /// + /// Gets the text that caused the + /// + /// event. + /// + /// + /// The text that caused the validation failure. + /// + public string Text { get; private set; } + + /// + /// Gets or sets a value indicating whether + /// + /// should be thrown. + /// + /// + /// True if the exception should be thrown; otherwise, false. + /// + /// + /// If set to true and + /// + /// is null. + /// + public bool ThrowException + { + get => _throwException; + set + { + if (value && Exception == null) + { + throw new ArgumentException("Cannot Throw Null Exception"); + } + + _throwException = value; + } + } + } +} From 764e28f8d8b865436a2b5ac6f1b8da64b77942fc Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 12:09:07 -0400 Subject: [PATCH 10/40] Move CalendarDatePickerFormat into its own file --- .../Calendar/CalendarDatePicker.cs | 24 -------------- ...rDatePickerDateValidationErrorEventArgs.cs | 7 ++++- .../Calendar/CalendarDatePickerFormat.cs | 31 +++++++++++++++++++ 3 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 src/Avalonia.Controls/Calendar/CalendarDatePickerFormat.cs diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index ddff1908c1..69ab518006 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -15,30 +15,6 @@ using Avalonia.Interactivity; namespace Avalonia.Controls { - /// - /// Specifies date formats for a - /// . - /// - public enum CalendarDatePickerFormat - { - /// - /// Specifies that the date should be displayed using unabbreviated days - /// of the week and month names. - /// - Long = 0, - - /// - /// Specifies that the date should be displayed using abbreviated days - /// of the week and month names. - /// - Short = 1, - - /// - /// Specifies that the date should be displayed using a custom format string. - /// - Custom = 2 - } - [TemplatePart(ElementButton, typeof(Button))] [TemplatePart(ElementCalendar, typeof(Calendar))] [TemplatePart(ElementPopup, typeof(Popup))] diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs b/src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs index ba7c579461..647910cb6b 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePickerDateValidationErrorEventArgs.cs @@ -1,4 +1,9 @@ -using System; +// (c) Copyright Microsoft Corporation. +// This source is subject to the Microsoft Public License (Ms-PL). +// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. +// All other rights reserved. + +using System; namespace Avalonia.Controls { diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePickerFormat.cs b/src/Avalonia.Controls/Calendar/CalendarDatePickerFormat.cs new file mode 100644 index 0000000000..4d96859d75 --- /dev/null +++ b/src/Avalonia.Controls/Calendar/CalendarDatePickerFormat.cs @@ -0,0 +1,31 @@ +// (c) Copyright Microsoft Corporation. +// This source is subject to the Microsoft Public License (Ms-PL). +// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. +// All other rights reserved. + +namespace Avalonia.Controls +{ + /// + /// Specifies date formats for a + /// . + /// + public enum CalendarDatePickerFormat + { + /// + /// Specifies that the date should be displayed using unabbreviated days + /// of the week and month names. + /// + Long = 0, + + /// + /// Specifies that the date should be displayed using abbreviated days + /// of the week and month names. + /// + Short = 1, + + /// + /// Specifies that the date should be displayed using a custom format string. + /// + Custom = 2 + } +} From 6912d27ed71616ad1a98199f9d0052cb0d602be5 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 12:59:14 -0400 Subject: [PATCH 11/40] Add :pressed and :flyout-open PseudoClasses to CalendarDatePicker --- .../Calendar/CalendarDatePicker.cs | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 69ab518006..fbd3f36aea 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -7,6 +7,7 @@ using System; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; +using System.Reactive.Disposables; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Data; @@ -15,12 +16,19 @@ using Avalonia.Interactivity; namespace Avalonia.Controls { + /// + /// A date selection control that allows the user to select dates from a drop down calendar. + /// [TemplatePart(ElementButton, typeof(Button))] [TemplatePart(ElementCalendar, typeof(Calendar))] [TemplatePart(ElementPopup, typeof(Popup))] [TemplatePart(ElementTextBox, typeof(TextBox))] + [PseudoClasses(pcFlyoutOpen, pcPressed)] public partial class CalendarDatePicker : TemplatedControl { + protected const string pcPressed = ":pressed"; + protected const string pcFlyoutOpen = ":flyout-open"; + private const string ElementTextBox = "PART_TextBox"; private const string ElementButton = "PART_Button"; private const string ElementPopup = "PART_Popup"; @@ -29,8 +37,6 @@ namespace Avalonia.Controls private Calendar? _calendar; private string _defaultText; private Button? _dropDownButton; - //private Canvas _outsideCanvas; - //private Canvas _outsidePopupCanvas; private Popup? _popUp; private TextBox? _textBox; private IDisposable? _textBoxTextChangedSubscription; @@ -48,6 +54,8 @@ namespace Avalonia.Controls private bool _suspendTextChangeHandler = false; private bool _isPopupClosing = false; private bool _ignoreButtonClick = false; + private bool _isFlyoutOpen = false; + private bool _isPressed = false; /// /// Occurs when the drop-down @@ -80,8 +88,7 @@ namespace Avalonia.Controls } /// - /// Initializes a new instance of the - /// class. + /// Initializes a new instance of the class. /// public CalendarDatePicker() { @@ -90,6 +97,15 @@ namespace Avalonia.Controls DisplayDate = DateTime.Today; } + /// + /// Updates the visual state of the control by applying latest PseudoClasses. + /// + protected void UpdatePseudoClasses() + { + PseudoClasses.Set(pcFlyoutOpen, _isFlyoutOpen); + PseudoClasses.Set(pcPressed, _isPressed); + } + /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { @@ -147,8 +163,9 @@ namespace Avalonia.Controls if(_dropDownButton != null) { _dropDownButton.Click += DropDownButton_Click; - _buttonPointerPressedSubscription = - _dropDownButton.AddDisposableHandler(PointerPressedEvent, DropDownButton_PointerPressed, handledEventsToo: true); + _buttonPointerPressedSubscription = new CompositeDisposable( + _dropDownButton.AddDisposableHandler(PointerPressedEvent, DropDownButton_PointerPressed, handledEventsToo: true), + _dropDownButton.AddDisposableHandler(PointerReleasedEvent, DropDownButton_PointerReleased, handledEventsToo: true)); } if (_textBox != null) @@ -180,6 +197,8 @@ namespace Avalonia.Controls SetSelectedDate(); } } + + UpdatePseudoClasses(); } /// @@ -215,6 +234,10 @@ namespace Avalonia.Controls else { _popUp.IsOpen = false; + _isFlyoutOpen = _popUp.IsOpen; + _isPressed = false; + + UpdatePseudoClasses(); OnCalendarClosed(new RoutedEventArgs()); } } @@ -516,6 +539,15 @@ namespace Avalonia.Controls private void DropDownButton_PointerPressed(object? sender, PointerPressedEventArgs e) { _ignoreButtonClick = _isPopupClosing; + + _isPressed = true; + UpdatePseudoClasses(); + } + + private void DropDownButton_PointerReleased(object? sender, PointerReleasedEventArgs e) + { + _isPressed = false; + UpdatePseudoClasses(); } private void DropDownButton_Click(object? sender, RoutedEventArgs e) @@ -559,18 +591,18 @@ namespace Avalonia.Controls if (_calendar != null) { _calendar.Focus(); - OpenPopUp(); + + // Open the PopUp + _onOpenSelectedDate = SelectedDate; + _popUp!.IsOpen = true; + _isFlyoutOpen = _popUp!.IsOpen; + + UpdatePseudoClasses(); _calendar.ResetStates(); OnCalendarOpened(new RoutedEventArgs()); } } - private void OpenPopUp() - { - _onOpenSelectedDate = SelectedDate; - _popUp!.IsOpen = true; - } - /// /// Input text is parsed in the correct format and changed into a /// DateTime object. If the text can not be parsed TextParseError Event From 6bde8b185e73be958b2db324f550fe6e411c50d3 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 15:37:47 -0400 Subject: [PATCH 12/40] Rewrite the Fluent CalendarDatePicker style --- .../Accents/FluentControlResourcesDark.xaml | 17 +- .../Accents/FluentControlResourcesLight.xaml | 17 +- .../Controls/CalendarDatePicker.xaml | 241 ++++++++++-------- 3 files changed, 164 insertions(+), 111 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml index 5b86de02d5..c5bb70bed3 100644 --- a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml +++ b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesDark.xaml @@ -587,9 +587,24 @@ - + + + + + + + + + + + + + + + + 1 diff --git a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml index eb68270354..8d38d39bd5 100644 --- a/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml +++ b/src/Avalonia.Themes.Fluent/Accents/FluentControlResourcesLight.xaml @@ -581,9 +581,24 @@ - + + + + + + + + + + + + + + + + 1 diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index 4e0c7082c7..c5a219540b 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -30,125 +30,148 @@ + + - - - - - - - - - - - - - - - - - /// - /// The date to display. The default - /// . + /// The date to display. The default is . /// - /// + /// /// The specified date is not in the range defined by - /// + /// /// and - /// . + /// . /// public DateTime DisplayDate { @@ -215,11 +214,11 @@ namespace Avalonia.Controls /// /// /// The specified date is not in the range defined by - /// + /// /// and - /// , + /// , /// or the specified date is in the - /// + /// /// collection. /// public DateTime? SelectedDate @@ -233,9 +232,9 @@ namespace Avalonia.Controls /// /// /// The format that is used to display the selected date. The default is - /// . + /// . /// - /// + /// /// An specified format is not valid. /// public CalendarDatePickerFormat SelectedDateFormat @@ -251,18 +250,16 @@ namespace Avalonia.Controls } /// - /// Gets or sets the text that is displayed by the - /// . + /// Gets or sets the text that is displayed by the . /// /// - /// The text displayed by the - /// . + /// The text displayed by the . /// - /// + /// /// The text entered cannot be parsed to a valid date, and the exception /// is not suppressed. /// - /// + /// /// The text entered parses to a date that is not selectable. /// public string? Text From b0246965b8a72cc33403093919acfb449bc21c38 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:00:08 -0400 Subject: [PATCH 15/40] Modernize TextBox property accessor code --- src/Avalonia.Controls/TextBox.cs | 94 ++++++++++++++------------------ 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index ce7d2f7e5f..82346599a4 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -239,23 +239,19 @@ namespace Avalonia.Controls public bool AcceptsReturn { - get { return GetValue(AcceptsReturnProperty); } - set { SetValue(AcceptsReturnProperty, value); } + get => GetValue(AcceptsReturnProperty); + set => SetValue(AcceptsReturnProperty, value); } public bool AcceptsTab { - get { return GetValue(AcceptsTabProperty); } - set { SetValue(AcceptsTabProperty, value); } + get => GetValue(AcceptsTabProperty); + set => SetValue(AcceptsTabProperty, value); } public int CaretIndex { - get - { - return _caretIndex; - } - + get => _caretIndex; set { value = CoerceCaretIndex(value); @@ -271,8 +267,8 @@ namespace Avalonia.Controls public bool IsReadOnly { - get { return GetValue(IsReadOnlyProperty); } - set { SetValue(IsReadOnlyProperty, value); } + get => GetValue(IsReadOnlyProperty); + set => SetValue(IsReadOnlyProperty, value); } public char PasswordChar @@ -301,11 +297,7 @@ namespace Avalonia.Controls public int SelectionStart { - get - { - return _selectionStart; - } - + get => _selectionStart; set { value = CoerceCaretIndex(value); @@ -325,11 +317,7 @@ namespace Avalonia.Controls public int SelectionEnd { - get - { - return _selectionEnd; - } - + get => _selectionEnd; set { value = CoerceCaretIndex(value); @@ -349,20 +337,20 @@ namespace Avalonia.Controls public int MaxLength { - get { return GetValue(MaxLengthProperty); } - set { SetValue(MaxLengthProperty, value); } + get => GetValue(MaxLengthProperty); + set => SetValue(MaxLengthProperty, value); } public int MaxLines { - get { return GetValue(MaxLinesProperty); } - set { SetValue(MaxLinesProperty, value); } + get => GetValue(MaxLinesProperty); + set => SetValue(MaxLinesProperty, value); } [Content] public string? Text { - get { return _text; } + get => _text; set { if (!_ignoreTextChanges) @@ -386,7 +374,7 @@ namespace Avalonia.Controls public string SelectedText { - get { return GetSelection(); } + get => GetSelection(); set { if (string.IsNullOrEmpty(value)) @@ -407,8 +395,8 @@ namespace Avalonia.Controls /// public HorizontalAlignment HorizontalContentAlignment { - get { return GetValue(HorizontalContentAlignmentProperty); } - set { SetValue(HorizontalContentAlignmentProperty, value); } + get => GetValue(HorizontalContentAlignmentProperty); + set => SetValue(HorizontalContentAlignmentProperty, value); } /// @@ -416,14 +404,14 @@ namespace Avalonia.Controls /// public VerticalAlignment VerticalContentAlignment { - get { return GetValue(VerticalContentAlignmentProperty); } - set { SetValue(VerticalContentAlignmentProperty, value); } + get => GetValue(VerticalContentAlignmentProperty); + set => SetValue(VerticalContentAlignmentProperty, value); } public TextAlignment TextAlignment { - get { return GetValue(TextAlignmentProperty); } - set { SetValue(TextAlignmentProperty, value); } + get => GetValue(TextAlignmentProperty); + set => SetValue(TextAlignmentProperty, value); } /// @@ -448,26 +436,26 @@ namespace Avalonia.Controls public object InnerLeftContent { - get { return GetValue(InnerLeftContentProperty); } - set { SetValue(InnerLeftContentProperty, value); } + get => GetValue(InnerLeftContentProperty); + set => SetValue(InnerLeftContentProperty, value); } public object InnerRightContent { - get { return GetValue(InnerRightContentProperty); } - set { SetValue(InnerRightContentProperty, value); } + get => GetValue(InnerRightContentProperty); + set => SetValue(InnerRightContentProperty, value); } public bool RevealPassword { - get { return GetValue(RevealPasswordProperty); } - set { SetValue(RevealPasswordProperty, value); } + get => GetValue(RevealPasswordProperty); + set => SetValue(RevealPasswordProperty, value); } public TextWrapping TextWrapping { - get { return GetValue(TextWrappingProperty); } - set { SetValue(TextWrappingProperty, value); } + get => GetValue(TextWrappingProperty); + set => SetValue(TextWrappingProperty, value); } /// @@ -475,8 +463,8 @@ namespace Avalonia.Controls /// public string NewLine { - get { return _newLine; } - set { SetAndRaise(NewLineProperty, ref _newLine, value); } + get => _newLine; + set => SetAndRaise(NewLineProperty, ref _newLine, value); } /// @@ -492,8 +480,8 @@ namespace Avalonia.Controls /// public bool CanCut { - get { return _canCut; } - private set { SetAndRaise(CanCutProperty, ref _canCut, value); } + get => _canCut; + private set => SetAndRaise(CanCutProperty, ref _canCut, value); } /// @@ -501,8 +489,8 @@ namespace Avalonia.Controls /// public bool CanCopy { - get { return _canCopy; } - private set { SetAndRaise(CanCopyProperty, ref _canCopy, value); } + get => _canCopy; + private set => SetAndRaise(CanCopyProperty, ref _canCopy, value); } /// @@ -510,8 +498,8 @@ namespace Avalonia.Controls /// public bool CanPaste { - get { return _canPaste; } - private set { SetAndRaise(CanPasteProperty, ref _canPaste, value); } + get => _canPaste; + private set => SetAndRaise(CanPasteProperty, ref _canPaste, value); } /// @@ -519,13 +507,13 @@ namespace Avalonia.Controls /// public bool IsUndoEnabled { - get { return GetValue(IsUndoEnabledProperty); } - set { SetValue(IsUndoEnabledProperty, value); } + get => GetValue(IsUndoEnabledProperty); + set => SetValue(IsUndoEnabledProperty, value); } public int UndoLimit { - get { return _undoRedoHelper.Limit; } + get => _undoRedoHelper.Limit; set { if (_undoRedoHelper.Limit != value) @@ -1544,7 +1532,7 @@ namespace Avalonia.Controls UndoRedoState UndoRedoHelper.IUndoRedoHost.UndoRedoState { - get { return new UndoRedoState(Text, CaretIndex); } + get => new UndoRedoState(Text, CaretIndex); set { Text = value.Text; From b043db169cc02d1018ed02c95ea41231acf4a010 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:15:34 -0400 Subject: [PATCH 16/40] Make sure to call base methods in Button --- src/Avalonia.Controls/Button.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index a4d15bab8d..9a7853cd4b 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -309,6 +309,8 @@ namespace Avalonia.Controls IsPressed = false; e.Handled = true; } + + base.OnKeyUp(e); } /// @@ -393,6 +395,8 @@ namespace Avalonia.Controls /// protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e) { + base.OnPointerCaptureLost(e); + IsPressed = false; } @@ -407,6 +411,8 @@ namespace Avalonia.Controls /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { + base.OnApplyTemplate(e); + UnregisterFlyoutEvents(Flyout); RegisterFlyoutEvents(Flyout); UpdatePseudoClasses(); From 0329a8daa1ceef647d89f3ccece0ca1e94e544ec Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:18:34 -0400 Subject: [PATCH 17/40] Support opening the calendar flyout when pressing outside the button --- .../Calendar/CalendarDatePicker.cs | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index fbd3f36aea..1f9b457c42 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -331,6 +331,7 @@ namespace Avalonia.Controls base.OnPropertyChanged(change); } + /// protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value) { if (property == SelectedDateProperty) @@ -339,6 +340,55 @@ namespace Avalonia.Controls } } + /// + protected override void OnPointerPressed(PointerPressedEventArgs e) + { + base.OnPointerPressed(e); + + if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + { + e.Handled = true; + + _ignoreButtonClick = _isPopupClosing; + + _isPressed = true; + UpdatePseudoClasses(); + } + } + + /// + protected override void OnPointerReleased(PointerReleasedEventArgs e) + { + base.OnPointerReleased(e); + + if (_isPressed && e.InitialPressMouseButton == MouseButton.Left) + { + e.Handled = true; + + if (!_ignoreButtonClick) + { + HandlePopUp(); + } + else + { + _ignoreButtonClick = false; + } + + _isPressed = false; + UpdatePseudoClasses(); + } + } + + /// + protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e) + { + base.OnPointerCaptureLost(e); + + _isPressed = false; + UpdatePseudoClasses(); + } + + /// protected override void OnPointerWheelChanged(PointerWheelEventArgs e) { base.OnPointerWheelChanged(e); @@ -354,6 +404,7 @@ namespace Avalonia.Controls } } + /// protected override void OnGotFocus(GotFocusEventArgs e) { base.OnGotFocus(e); @@ -369,10 +420,14 @@ namespace Avalonia.Controls } } + /// protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e); + _isPressed = false; + UpdatePseudoClasses(); + SetSelectedDate(); } @@ -671,7 +726,6 @@ namespace Avalonia.Controls private bool ProcessDatePickerKey(KeyEventArgs e) { - switch (e.Key) { case Key.Enter: From 24a3dc560aaed3f7208bce05b190f4b79a3695fd Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:23:39 -0400 Subject: [PATCH 18/40] Better support MinHeight --- src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index c5a219540b..00f53a563d 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -19,6 +19,7 @@ 12 + 32 - + + + + + + From dbe46697c9e75b3d77afed712321695e679588d0 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 20:21:53 -0400 Subject: [PATCH 20/40] Improve CalendarDatePicker Fluent style --- .../Controls/CalendarDatePicker.xaml | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index e030e14243..592581e975 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -23,7 +23,6 @@ - - - + - +