From 3b7d8574e8782591bf007f31b0f3b140425bae2a Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 4 Jun 2020 23:17:42 +0200 Subject: [PATCH 1/7] Try matching for INPC before matching methods. --- .../Plugins/InpcPropertyAccessorPlugin.cs | 15 +++-- .../Data/Core/PropertyAccessorNode.cs | 9 ++- .../Core/ExpressionObserverTests_Property.cs | 2 +- .../Data/AccessorTestObject.cs | 47 +++++++++++++++ .../Data/PropertyAccessorBenchmarks.cs | 54 ++--------------- .../Data/PropertyAccessorPluginBenchmarks.cs | 60 +++++++++++++++++++ ...ExpressionObserverBuilderTests_Property.cs | 2 +- 7 files changed, 131 insertions(+), 58 deletions(-) create mode 100644 tests/Avalonia.Benchmarks/Data/AccessorTestObject.cs create mode 100644 tests/Avalonia.Benchmarks/Data/PropertyAccessorPluginBenchmarks.cs diff --git a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs index 84ef0fb695..8fc2a7b77c 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs @@ -12,7 +12,7 @@ namespace Avalonia.Data.Core.Plugins public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin { /// - public bool Match(object obj, string propertyName) => true; + public bool Match(object obj, string propertyName) => GetPropertyWithName(obj.GetType(), propertyName) != null; /// /// Starts monitoring the value of a property on an object. @@ -30,10 +30,7 @@ namespace Avalonia.Data.Core.Plugins reference.TryGetTarget(out object instance); - const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | - BindingFlags.Static | BindingFlags.Instance; - - var p = instance.GetType().GetProperty(propertyName, bindingFlags); + var p = GetPropertyWithName(instance.GetType(), propertyName); if (p != null) { @@ -47,6 +44,14 @@ namespace Avalonia.Data.Core.Plugins } } + private static PropertyInfo GetPropertyWithName(Type type, string propertyName) + { + const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | + BindingFlags.Static | BindingFlags.Instance; + + return type.GetProperty(propertyName, bindingFlags); + } + private class Accessor : PropertyAccessorBase, IWeakSubscriber { private readonly WeakReference _reference; diff --git a/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs b/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs index e20685b1dd..a0868152f6 100644 --- a/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs +++ b/src/Avalonia.Base/Data/Core/PropertyAccessorNode.cs @@ -62,8 +62,13 @@ namespace Avalonia.Data.Core if (accessor == null) { - throw new NotSupportedException( - $"Could not find a matching property accessor for {PropertyName}."); + reference.TryGetTarget(out object instance); + + var message = $"Could not find a matching property accessor for '{PropertyName}' on '{instance}'"; + + var exception = new MissingMemberException(message); + + accessor = new PropertyError(new BindingNotification(exception, BindingErrorType.Error)); } _accessor = accessor; diff --git a/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs b/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs index 6e175707e4..df871a67b4 100644 --- a/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs +++ b/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs @@ -322,7 +322,7 @@ namespace Avalonia.Base.UnitTests.Data.Core { "bar", new BindingNotification( - new MissingMemberException("Could not find CLR property 'Bar' on 'Avalonia.Base.UnitTests.Data.Core.ExpressionObserverTests_Property+WithoutBar'"), + new MissingMemberException("Could not find a matching property accessor for 'Bar' on 'Avalonia.Base.UnitTests.Data.Core.ExpressionObserverTests_Property+WithoutBar'"), BindingErrorType.Error), "baz", }, diff --git a/tests/Avalonia.Benchmarks/Data/AccessorTestObject.cs b/tests/Avalonia.Benchmarks/Data/AccessorTestObject.cs new file mode 100644 index 0000000000..0039f5670c --- /dev/null +++ b/tests/Avalonia.Benchmarks/Data/AccessorTestObject.cs @@ -0,0 +1,47 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; +using JetBrains.Annotations; + +namespace Avalonia.Benchmarks.Data +{ + internal class AccessorTestObject : INotifyPropertyChanged + { + private string _test; + + public string Test + { + get => _test; + set + { + if (_test == value) + { + return; + } + + _test = value; + + OnPropertyChanged(); + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void Execute() + { + } + + public void Execute(object p0) + { + } + + public void Execute(object p0, object p1) + { + } + + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/tests/Avalonia.Benchmarks/Data/PropertyAccessorBenchmarks.cs b/tests/Avalonia.Benchmarks/Data/PropertyAccessorBenchmarks.cs index 3d5a4029bb..6c5e0d3b53 100644 --- a/tests/Avalonia.Benchmarks/Data/PropertyAccessorBenchmarks.cs +++ b/tests/Avalonia.Benchmarks/Data/PropertyAccessorBenchmarks.cs @@ -1,9 +1,6 @@ using System; -using System.ComponentModel; -using System.Runtime.CompilerServices; using Avalonia.Data.Core.Plugins; using BenchmarkDotNet.Attributes; -using JetBrains.Annotations; namespace Avalonia.Benchmarks.Data { @@ -12,7 +9,7 @@ namespace Avalonia.Benchmarks.Data { private readonly InpcPropertyAccessorPlugin _inpcPlugin = new InpcPropertyAccessorPlugin(); private readonly MethodAccessorPlugin _methodPlugin = new MethodAccessorPlugin(); - private readonly TestObject _targetStrongRef = new TestObject(); + private readonly AccessorTestObject _targetStrongRef = new AccessorTestObject(); private readonly WeakReference _targetWeakRef; public PropertyAccessorBenchmarks() @@ -23,66 +20,25 @@ namespace Avalonia.Benchmarks.Data [Benchmark] public void InpcAccessorMatch() { - _inpcPlugin.Match(_targetWeakRef, nameof(TestObject.Test)); + _inpcPlugin.Match(_targetWeakRef, nameof(AccessorTestObject.Test)); } [Benchmark] public void InpcAccessorStart() { - _inpcPlugin.Start(_targetWeakRef, nameof(TestObject.Test)); + _inpcPlugin.Start(_targetWeakRef, nameof(AccessorTestObject.Test)); } [Benchmark] public void MethodAccessorMatch() { - _methodPlugin.Match(_targetWeakRef, nameof(TestObject.Execute)); + _methodPlugin.Match(_targetWeakRef, nameof(AccessorTestObject.Execute)); } [Benchmark] public void MethodAccessorStart() { - _methodPlugin.Start(_targetWeakRef, nameof(TestObject.Execute)); - } - - private class TestObject : INotifyPropertyChanged - { - private string _test; - - public string Test - { - get => _test; - set - { - if (_test == value) - { - return; - } - - _test = value; - - OnPropertyChanged(); - } - } - - public void Execute() - { - } - - public void Execute(object p0) - { - } - - public void Execute(object p0, object p1) - { - } - - public event PropertyChangedEventHandler PropertyChanged; - - [NotifyPropertyChangedInvocator] - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } + _methodPlugin.Start(_targetWeakRef, nameof(AccessorTestObject.Execute)); } } } diff --git a/tests/Avalonia.Benchmarks/Data/PropertyAccessorPluginBenchmarks.cs b/tests/Avalonia.Benchmarks/Data/PropertyAccessorPluginBenchmarks.cs new file mode 100644 index 0000000000..75e3269e3d --- /dev/null +++ b/tests/Avalonia.Benchmarks/Data/PropertyAccessorPluginBenchmarks.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using Avalonia.Data.Core.Plugins; +using BenchmarkDotNet.Attributes; + +namespace Avalonia.Benchmarks.Data +{ + [MemoryDiagnoser, InProcess] + public class PropertyAccessorPluginBenchmarks + { + private readonly AccessorTestObject _targetStrongRef = new AccessorTestObject(); + + private readonly List _oldPlugins; + private readonly List _newPlugins; + + public PropertyAccessorPluginBenchmarks() + { + _oldPlugins = new List + { + new AvaloniaPropertyAccessorPlugin(), + new MethodAccessorPlugin(), + new InpcPropertyAccessorPlugin() + }; + + _newPlugins = new List + { + new AvaloniaPropertyAccessorPlugin(), + new InpcPropertyAccessorPlugin(), + new MethodAccessorPlugin() + }; + } + + [Benchmark] + public void MatchAccessorOld() + { + var propertyName = nameof(AccessorTestObject.Test); + + foreach (IPropertyAccessorPlugin x in _oldPlugins) + { + if (x.Match(_targetStrongRef, propertyName)) + { + break; + } + } + } + + [Benchmark] + public void MatchAccessorNew() + { + var propertyName = nameof(AccessorTestObject.Test); + + foreach (IPropertyAccessorPlugin x in _newPlugins) + { + if (x.Match(_targetStrongRef, propertyName)) + { + break; + } + } + } + } +} diff --git a/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Property.cs b/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Property.cs index 4f7264f2f2..8cf74c36f4 100644 --- a/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Property.cs +++ b/tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Property.cs @@ -22,7 +22,7 @@ namespace Avalonia.Markup.UnitTests.Parsers Assert.Equal( new BindingNotification( - new MissingMemberException("Could not find CLR property 'Baz' on '1'"), BindingErrorType.Error), + new MissingMemberException("Could not find a matching property accessor for 'Baz' on '1'"), BindingErrorType.Error), result); GC.KeepAlive(data); From de0f3285d47d268232196d117c4bccc6a9e5de4c Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 10 Jun 2020 19:10:18 -0400 Subject: [PATCH 2/7] Revert RepeatButton style removing --- src/Avalonia.Themes.Fluent/Button.xaml | 25 ++++++------ src/Avalonia.Themes.Fluent/FluentTheme.xaml | 1 + src/Avalonia.Themes.Fluent/RepeatButton.xaml | 40 ++++++++++++++++++++ 3 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 src/Avalonia.Themes.Fluent/RepeatButton.xaml diff --git a/src/Avalonia.Themes.Fluent/Button.xaml b/src/Avalonia.Themes.Fluent/Button.xaml index 3336e611c1..ee8060f823 100644 --- a/src/Avalonia.Themes.Fluent/Button.xaml +++ b/src/Avalonia.Themes.Fluent/Button.xaml @@ -4,14 +4,13 @@ - + + From 19b1cdc46fc0b15ca476688cc165a2dffe53dcf2 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 12 Jun 2020 21:44:55 -0400 Subject: [PATCH 6/7] Fluent ToggleButton --- src/Avalonia.Themes.Fluent/ToggleButton.xaml | 113 +++++++++++++++---- 1 file changed, 92 insertions(+), 21 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/ToggleButton.xaml b/src/Avalonia.Themes.Fluent/ToggleButton.xaml index 9e05c38eef..2e9bd4c825 100644 --- a/src/Avalonia.Themes.Fluent/ToggleButton.xaml +++ b/src/Avalonia.Themes.Fluent/ToggleButton.xaml @@ -1,38 +1,109 @@ - + + + + + + + + + + + + + 8,5,8,6 + - + + + + + + + + + + + + + + + + + + + - - \ No newline at end of file + From 0863b29d0924e43775a8666644bc59d917a81dc4 Mon Sep 17 00:00:00 2001 From: amwx Date: Thu, 11 Jun 2020 19:32:28 -0500 Subject: [PATCH 7/7] Rename existing DatePicker control --- samples/ControlCatalog/MainView.xaml | 3 +- ...rPage.xaml => CalendarDatePickerPage.xaml} | 18 +-- ...xaml.cs => CalendarDatePickerPage.xaml.cs} | 14 +- src/Avalonia.Controls/Calendar/Calendar.cs | 4 +- .../{DatePicker.cs => CalendarDatePicker.cs} | 134 +++++++++--------- .../Calendar/CalendarItem.cs | 4 +- .../CalendarDatePicker.xaml} | 4 +- src/Avalonia.Themes.Default/DefaultTheme.xaml | 2 +- .../CalendarDatePicker.xaml} | 4 +- src/Avalonia.Themes.Fluent/FluentTheme.xaml | 2 +- ...kerTests.cs => CalendarDatePickerTests.cs} | 14 +- 11 files changed, 102 insertions(+), 101 deletions(-) rename samples/ControlCatalog/Pages/{DatePickerPage.xaml => CalendarDatePickerPage.xaml} (75%) rename samples/ControlCatalog/Pages/{DatePickerPage.xaml.cs => CalendarDatePickerPage.xaml.cs} (57%) rename src/Avalonia.Controls/Calendar/{DatePicker.cs => CalendarDatePicker.cs} (87%) rename src/{Avalonia.Themes.Fluent/DatePicker.xaml => Avalonia.Themes.Default/CalendarDatePicker.xaml} (97%) rename src/{Avalonia.Themes.Default/DatePicker.xaml => Avalonia.Themes.Fluent/CalendarDatePicker.xaml} (97%) rename tests/Avalonia.Controls.UnitTests/{DatePickerTests.cs => CalendarDatePickerTests.cs} (90%) diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 7956ee6169..af2d093bc7 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -29,7 +29,8 @@ ScrollViewer.HorizontalScrollBarVisibility="Disabled"> - + + + x:Class="ControlCatalog.Pages.CalendarDatePickerPage"> - DatePicker + CalendarDatePicker A control for selecting dates with a calendar drop-down - - - - - - - + diff --git a/samples/ControlCatalog/Pages/DatePickerPage.xaml.cs b/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs similarity index 57% rename from samples/ControlCatalog/Pages/DatePickerPage.xaml.cs rename to samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs index ef01887c9e..95bdeb363a 100644 --- a/samples/ControlCatalog/Pages/DatePickerPage.xaml.cs +++ b/samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs @@ -4,17 +4,17 @@ using System; namespace ControlCatalog.Pages { - public class DatePickerPage : UserControl + public class CalendarDatePickerPage : UserControl { - public DatePickerPage() + public CalendarDatePickerPage() { InitializeComponent(); - var dp1 = this.FindControl("DatePicker1"); - var dp2 = this.FindControl("DatePicker2"); - var dp3 = this.FindControl("DatePicker3"); - var dp4 = this.FindControl("DatePicker4"); - var dp5 = this.FindControl("DatePicker5"); + var dp1 = this.FindControl("DatePicker1"); + var dp2 = this.FindControl("DatePicker2"); + var dp3 = this.FindControl("DatePicker3"); + var dp4 = this.FindControl("DatePicker4"); + var dp5 = this.FindControl("DatePicker5"); dp1.SelectedDate = DateTime.Today; dp2.SelectedDate = DateTime.Today.AddDays(10); diff --git a/src/Avalonia.Controls/Calendar/Calendar.cs b/src/Avalonia.Controls/Calendar/Calendar.cs index 53c6a54b4d..4cf7db74d9 100644 --- a/src/Avalonia.Controls/Calendar/Calendar.cs +++ b/src/Avalonia.Controls/Calendar/Calendar.cs @@ -998,10 +998,10 @@ namespace Avalonia.Controls /// - /// Gets or sets a value indicating whether DatePicker should change its + /// Gets or sets a value indicating whether CalendarDatePicker should change its /// DisplayDate because of a SelectedDate change on its Calendar. /// - internal bool DatePickerDisplayDateFlag { get; set; } + internal bool CalendarDatePickerDisplayDateFlag { get; set; } internal CalendarDayButton FindDayButtonFromDay(DateTime day) { diff --git a/src/Avalonia.Controls/Calendar/DatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs similarity index 87% rename from src/Avalonia.Controls/Calendar/DatePicker.cs rename to src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 0f53dc1364..b987f065be 100644 --- a/src/Avalonia.Controls/Calendar/DatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -16,29 +16,29 @@ namespace Avalonia.Controls { /// /// Provides data for the - /// + /// /// event. /// - public class DatePickerDateValidationErrorEventArgs : EventArgs + 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 DatePickerDateValidationErrorEventArgs(Exception exception, string text) + public CalendarDatePickerDateValidationErrorEventArgs(Exception exception, string text) { this.Text = text; this.Exception = exception; @@ -46,7 +46,7 @@ namespace Avalonia.Controls /// /// Gets the initial exception associated with the - /// + /// /// event. /// /// @@ -56,7 +56,7 @@ namespace Avalonia.Controls /// /// Gets the text that caused the - /// + /// /// event. /// /// @@ -66,7 +66,7 @@ namespace Avalonia.Controls /// /// Gets or sets a value indicating whether - /// + /// /// should be thrown. /// /// @@ -74,7 +74,7 @@ namespace Avalonia.Controls /// /// /// If set to true and - /// + /// /// is null. /// public bool ThrowException @@ -93,9 +93,9 @@ namespace Avalonia.Controls /// /// Specifies date formats for a - /// . + /// . /// - public enum DatePickerFormat + public enum CalendarDatePickerFormat { /// /// Specifies that the date should be displayed using unabbreviated days @@ -115,7 +115,7 @@ namespace Avalonia.Controls Custom = 2 } - public class DatePicker : TemplatedControl + public class CalendarDatePicker : TemplatedControl { private const string ElementTextBox = "PART_TextBox"; private const string ElementButton = "PART_Button"; @@ -154,59 +154,59 @@ namespace Avalonia.Controls /// public CalendarBlackoutDatesCollection BlackoutDates { get; private set; } - public static readonly DirectProperty DisplayDateProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty DisplayDateProperty = + AvaloniaProperty.RegisterDirect( nameof(DisplayDate), o => o.DisplayDate, (o, v) => o.DisplayDate = v); - public static readonly DirectProperty DisplayDateStartProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty DisplayDateStartProperty = + AvaloniaProperty.RegisterDirect( nameof(DisplayDateStart), o => o.DisplayDateStart, (o, v) => o.DisplayDateStart = v); - public static readonly DirectProperty DisplayDateEndProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty DisplayDateEndProperty = + AvaloniaProperty.RegisterDirect( nameof(DisplayDateEnd), o => o.DisplayDateEnd, (o, v) => o.DisplayDateEnd = v); public static readonly StyledProperty FirstDayOfWeekProperty = - AvaloniaProperty.Register(nameof(FirstDayOfWeek)); + AvaloniaProperty.Register(nameof(FirstDayOfWeek)); - public static readonly DirectProperty IsDropDownOpenProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty IsDropDownOpenProperty = + AvaloniaProperty.RegisterDirect( nameof(IsDropDownOpen), o => o.IsDropDownOpen, (o, v) => o.IsDropDownOpen = v); public static readonly StyledProperty IsTodayHighlightedProperty = - AvaloniaProperty.Register(nameof(IsTodayHighlighted)); - public static readonly DirectProperty SelectedDateProperty = - AvaloniaProperty.RegisterDirect( + AvaloniaProperty.Register(nameof(IsTodayHighlighted)); + public static readonly DirectProperty SelectedDateProperty = + AvaloniaProperty.RegisterDirect( nameof(SelectedDate), o => o.SelectedDate, (o, v) => o.SelectedDate = v); - public static readonly StyledProperty SelectedDateFormatProperty = - AvaloniaProperty.Register( + public static readonly StyledProperty SelectedDateFormatProperty = + AvaloniaProperty.Register( nameof(SelectedDateFormat), - defaultValue: DatePickerFormat.Short, + defaultValue: CalendarDatePickerFormat.Short, validate: IsValidSelectedDateFormat); public static readonly StyledProperty CustomDateFormatStringProperty = - AvaloniaProperty.Register( + AvaloniaProperty.Register( nameof(CustomDateFormatString), defaultValue: "d", validate: IsValidDateFormatString); - public static readonly DirectProperty TextProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty TextProperty = + AvaloniaProperty.RegisterDirect( nameof(Text), o => o.Text, (o, v) => o.Text = v); public static readonly StyledProperty WatermarkProperty = - TextBox.WatermarkProperty.AddOwner(); + TextBox.WatermarkProperty.AddOwner(); public static readonly StyledProperty UseFloatingWatermarkProperty = - TextBox.UseFloatingWatermarkProperty.AddOwner(); + TextBox.UseFloatingWatermarkProperty.AddOwner(); /// @@ -218,9 +218,9 @@ namespace Avalonia.Controls /// /// /// The specified date is not in the range defined by - /// + /// /// and - /// . + /// . /// public DateTime DisplayDate { @@ -320,7 +320,7 @@ namespace Avalonia.Controls /// /// An specified format is not valid. /// - public DatePickerFormat SelectedDateFormat + public CalendarDatePickerFormat SelectedDateFormat { get { return GetValue(SelectedDateFormatProperty); } set { SetValue(SelectedDateFormatProperty, value); } @@ -380,33 +380,33 @@ namespace Avalonia.Controls /// Occurs when /// is assigned a value that cannot be interpreted as a date. /// - public event EventHandler DateValidationError; + public event EventHandler DateValidationError; /// /// Occurs when the - /// + /// /// property is changed. /// public event EventHandler SelectedDateChanged; - static DatePicker() + static CalendarDatePicker() { - FocusableProperty.OverrideDefaultValue(true); - - DisplayDateProperty.Changed.AddClassHandler((x,e) => x.OnDisplayDateChanged(e)); - DisplayDateStartProperty.Changed.AddClassHandler((x,e) => x.OnDisplayDateStartChanged(e)); - DisplayDateEndProperty.Changed.AddClassHandler((x,e) => x.OnDisplayDateEndChanged(e)); - 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)); + FocusableProperty.OverrideDefaultValue(true); + + DisplayDateProperty.Changed.AddClassHandler((x,e) => x.OnDisplayDateChanged(e)); + DisplayDateStartProperty.Changed.AddClassHandler((x,e) => x.OnDisplayDateStartChanged(e)); + DisplayDateEndProperty.Changed.AddClassHandler((x,e) => x.OnDisplayDateEndChanged(e)); + 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)); } /// /// Initializes a new instance of the /// class. /// - public DatePicker() + public CalendarDatePicker() { FirstDayOfWeek = DateTimeHelper.GetCurrentDateFormat().FirstDayOfWeek; _defaultText = string.Empty; @@ -662,12 +662,12 @@ namespace Avalonia.Controls // 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.DatePickerDisplayDateFlag)) + if ((day.Month != DisplayDate.Month || day.Year != DisplayDate.Year) && (_calendar == null || !_calendar.CalendarDatePickerDisplayDateFlag)) { DisplayDate = day; } if(_calendar != null) - _calendar.DatePickerDisplayDateFlag = false; + _calendar.CalendarDatePickerDisplayDateFlag = false; } else { @@ -707,7 +707,7 @@ namespace Avalonia.Controls } private void OnCustomDateFormatStringChanged(AvaloniaPropertyChangedEventArgs e) { - if(SelectedDateFormat == DatePickerFormat.Custom) + if(SelectedDateFormat == CalendarDatePickerFormat.Custom) { OnDateFormatChanged(); } @@ -752,15 +752,15 @@ namespace Avalonia.Controls /// /// Raises the - /// + /// /// event. /// /// /// A - /// + /// /// that contains the event data. /// - protected virtual void OnDateValidationError(DatePickerDateValidationErrorEventArgs e) + protected virtual void OnDateValidationError(CalendarDatePickerDateValidationErrorEventArgs e) { DateValidationError?.Invoke(this, e); } @@ -959,7 +959,7 @@ namespace Avalonia.Controls } else { - var dateValidationError = new DatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException(nameof(text), "SelectedDate value is not valid."), text); + var dateValidationError = new CalendarDatePickerDateValidationErrorEventArgs(new ArgumentOutOfRangeException(nameof(text), "SelectedDate value is not valid."), text); OnDateValidationError(dateValidationError); if (dateValidationError.ThrowException) @@ -970,7 +970,7 @@ namespace Avalonia.Controls } catch (FormatException ex) { - DatePickerDateValidationErrorEventArgs textParseError = new DatePickerDateValidationErrorEventArgs(ex, text); + CalendarDatePickerDateValidationErrorEventArgs textParseError = new CalendarDatePickerDateValidationErrorEventArgs(ex, text); OnDateValidationError(textParseError); if (textParseError.ThrowException) @@ -986,11 +986,11 @@ namespace Avalonia.Controls switch (SelectedDateFormat) { - case DatePickerFormat.Short: + case CalendarDatePickerFormat.Short: return string.Format(CultureInfo.CurrentCulture, d.ToString(dtfi.ShortDatePattern, dtfi)); - case DatePickerFormat.Long: + case CalendarDatePickerFormat.Long: return string.Format(CultureInfo.CurrentCulture, d.ToString(dtfi.LongDatePattern, dtfi)); - case DatePickerFormat.Custom: + case CalendarDatePickerFormat.Custom: return string.Format(CultureInfo.CurrentCulture, d.ToString(CustomDateFormatString, dtfi)); } return null; @@ -1118,12 +1118,12 @@ namespace Avalonia.Controls switch (SelectedDateFormat) { - case DatePickerFormat.Long: + case CalendarDatePickerFormat.Long: { watermarkText = string.Format(CultureInfo.CurrentCulture, watermarkFormat, dtfi.LongDatePattern.ToString()); break; } - case DatePickerFormat.Short: + case CalendarDatePickerFormat.Short: default: { watermarkText = string.Format(CultureInfo.CurrentCulture, watermarkFormat, dtfi.ShortDatePattern.ToString()); @@ -1139,11 +1139,11 @@ namespace Avalonia.Controls } } - private static bool IsValidSelectedDateFormat(DatePickerFormat value) + private static bool IsValidSelectedDateFormat(CalendarDatePickerFormat value) { - return value == DatePickerFormat.Long - || value == DatePickerFormat.Short - || value == DatePickerFormat.Custom; + return value == CalendarDatePickerFormat.Long + || value == CalendarDatePickerFormat.Short + || value == CalendarDatePickerFormat.Custom; } private static bool IsValidDateFormatString(string formatString) { diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs index ece0ef97d9..0be7c4f67e 100644 --- a/src/Avalonia.Controls/Calendar/CalendarItem.cs +++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs @@ -909,7 +909,7 @@ namespace Avalonia.Controls.Primitives case CalendarSelectionMode.SingleDate: { DateTime selectedDate = (DateTime)b.DataContext; - Owner.DatePickerDisplayDateFlag = true; + Owner.CalendarDatePickerDisplayDateFlag = true; if (Owner.SelectedDates.Count == 0) { Owner.SelectedDates.Add(selectedDate); @@ -981,7 +981,7 @@ namespace Avalonia.Controls.Primitives } case CalendarSelectionMode.SingleDate: { - Owner.DatePickerDisplayDateFlag = true; + Owner.CalendarDatePickerDisplayDateFlag = true; if (Owner.SelectedDates.Count == 0) { Owner.SelectedDates.Add(selectedDate); diff --git a/src/Avalonia.Themes.Fluent/DatePicker.xaml b/src/Avalonia.Themes.Default/CalendarDatePicker.xaml similarity index 97% rename from src/Avalonia.Themes.Fluent/DatePicker.xaml rename to src/Avalonia.Themes.Default/CalendarDatePicker.xaml index 7adb1c2d5f..bc1aba1a03 100644 --- a/src/Avalonia.Themes.Fluent/DatePicker.xaml +++ b/src/Avalonia.Themes.Default/CalendarDatePicker.xaml @@ -8,7 +8,7 @@ - - diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml index 67279fca99..83da5d3142 100644 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -45,7 +45,7 @@ - + diff --git a/src/Avalonia.Themes.Default/DatePicker.xaml b/src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml similarity index 97% rename from src/Avalonia.Themes.Default/DatePicker.xaml rename to src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml index 7adb1c2d5f..bc1aba1a03 100644 --- a/src/Avalonia.Themes.Default/DatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/CalendarDatePicker.xaml @@ -8,7 +8,7 @@ - - diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.xaml b/src/Avalonia.Themes.Fluent/FluentTheme.xaml index a20f075e21..143b952163 100644 --- a/src/Avalonia.Themes.Fluent/FluentTheme.xaml +++ b/src/Avalonia.Themes.Fluent/FluentTheme.xaml @@ -44,7 +44,7 @@ - + diff --git a/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs b/tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs similarity index 90% rename from tests/Avalonia.Controls.UnitTests/DatePickerTests.cs rename to tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs index 3d396a9726..f41a3e7581 100644 --- a/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/CalendarDatePickerTests.cs @@ -15,7 +15,7 @@ using Xunit; namespace Avalonia.Controls.UnitTests { - public class DatePickerTests + public class CalendarDatePickerTests { private static bool CompareDates(DateTime first, DateTime second) { @@ -30,7 +30,7 @@ namespace Avalonia.Controls.UnitTests using (UnitTestApplication.Start(Services)) { bool handled = false; - DatePicker datePicker = CreateControl(); + CalendarDatePicker datePicker = CreateControl(); datePicker.SelectedDateChanged += (s,e) => { handled = true; @@ -47,7 +47,7 @@ namespace Avalonia.Controls.UnitTests { using (UnitTestApplication.Start(Services)) { - DatePicker datePicker = CreateControl(); + CalendarDatePicker datePicker = CreateControl(); datePicker.BlackoutDates.AddDatesInPast(); DateTime goodValue = DateTime.Today.AddDays(1); @@ -65,7 +65,7 @@ namespace Avalonia.Controls.UnitTests { using (UnitTestApplication.Start(Services)) { - DatePicker datePicker = CreateControl(); + CalendarDatePicker datePicker = CreateControl(); datePicker.SelectedDate = DateTime.Today.AddDays(5); Assert.ThrowsAny( @@ -76,10 +76,10 @@ namespace Avalonia.Controls.UnitTests private static TestServices Services => TestServices.MockThreadingInterface.With( standardCursorFactory: Mock.Of()); - private DatePicker CreateControl() + private CalendarDatePicker CreateControl() { var datePicker = - new DatePicker + new CalendarDatePicker { Template = CreateTemplate() }; @@ -90,7 +90,7 @@ namespace Avalonia.Controls.UnitTests private IControlTemplate CreateTemplate() { - return new FuncControlTemplate((control, scope) => + return new FuncControlTemplate((control, scope) => { var textBox = new TextBox