Browse Source

EnableDataValidation for DatePicker (#14430)

Ildar Khusnutdinov 1 year ago
parent
commit
e0fb7db6c5

+ 9 - 1
src/Avalonia.Controls/DateTimePickers/DatePicker.cs

@@ -78,7 +78,7 @@ namespace Avalonia.Controls
         /// </summary>
         public static readonly StyledProperty<DateTimeOffset?> SelectedDateProperty =
             AvaloniaProperty.Register<DatePicker, DateTimeOffset?>(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);
+        }
     }
 }

+ 41 - 0
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<DataValidationException>(() => datePicker.SelectedDate = new DateTimeOffset(1999, 1, 1, 0, 0, 0, TimeSpan.Zero));
+
+            // dateTime is over
+            Assert.Throws<DataValidationException>(() => datePicker.SelectedDate = new DateTimeOffset(2021, 1, 1, 0, 0, 0, TimeSpan.Zero));
+
+            var exception = new DataValidationException("failed validation");
+            var observable =
+                new BehaviorSubject<BindingNotification>(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<ICursorFactory>(),