From e0fb7db6c56f745027ef1b041ea0ca24feb27ab5 Mon Sep 17 00:00:00 2001 From: Ildar Khusnutdinov Date: Thu, 1 Feb 2024 15:49:18 +0400 Subject: [PATCH] EnableDataValidation for DatePicker (#14430) --- .../DateTimePickers/DatePicker.cs | 10 ++++- .../DatePickerTests.cs | 41 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs index 92b8671b51..c1f2a63f84 100644 --- a/src/Avalonia.Controls/DateTimePickers/DatePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/DatePicker.cs @@ -78,7 +78,7 @@ namespace Avalonia.Controls /// public static readonly StyledProperty SelectedDateProperty = AvaloniaProperty.Register(nameof(SelectedDate), - defaultBindingMode: BindingMode.TwoWay); + defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); // Template Items private Button? _flyoutButton; @@ -418,5 +418,13 @@ namespace Avalonia.Controls { SetCurrentValue(SelectedDateProperty, null); } + + protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error) + { + base.UpdateDataValidation(property, state, error); + + if (property == SelectedDateProperty) + DataValidationErrors.SetError(this, error); + } } } diff --git a/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs b/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs index 6c9aefc5a7..75ec7b7e59 100644 --- a/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/DatePickerTests.cs @@ -1,9 +1,12 @@ using System; using System.Linq; +using System.Reactive.Subjects; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; +using Avalonia.Data; using Avalonia.Headless; using Avalonia.Platform; +using Avalonia.Threading; using Avalonia.UnitTests; using Avalonia.VisualTree; using Moq; @@ -203,6 +206,44 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void SelectedDate_EnableDataValidation() + { + var handled = false; + var datePicker = new DatePicker(); + + datePicker.SelectedDateChanged += (s, e) => + { + var minDateTime = new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero); + var maxDateTime = new DateTimeOffset(2010, 1, 1, 0, 0, 0, TimeSpan.Zero); + + if (e.NewDate < minDateTime) + throw new DataValidationException($"dateTime is less than {minDateTime}"); + if (e.NewDate > maxDateTime) + throw new DataValidationException($"dateTime is over {maxDateTime}"); + + handled = true; + }; + + // dateTime is less than + Assert.Throws(() => datePicker.SelectedDate = new DateTimeOffset(1999, 1, 1, 0, 0, 0, TimeSpan.Zero)); + + // dateTime is over + Assert.Throws(() => datePicker.SelectedDate = new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero)); + + var exception = new DataValidationException("failed validation"); + var observable = + new BehaviorSubject(new BindingNotification(exception, + BindingErrorType.DataValidationError)); + datePicker.Bind(DatePicker.SelectedDateProperty, observable); + + Assert.True(DataValidationErrors.GetHasErrors(datePicker)); + + Dispatcher.UIThread.RunJobs(); + datePicker.SelectedDate = new DateTimeOffset(2005, 5, 10, 11, 12, 13, TimeSpan.Zero); + Assert.True(handled); + } + private static TestServices Services => TestServices.MockThreadingInterface.With( fontManagerImpl: new HeadlessFontManagerStub(), standardCursorFactory: Mock.Of(),