|
@@ -1,111 +1,153 @@
|
|
|
+using System;
|
|
|
using Avalonia.Controls;
|
|
|
+using Avalonia.Data;
|
|
|
using Avalonia.Markup.Xaml.Data;
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using System.ComponentModel;
|
|
|
-using System.Linq;
|
|
|
-using System.Runtime.CompilerServices;
|
|
|
-using System.Text;
|
|
|
-using System.Threading.Tasks;
|
|
|
using Xunit;
|
|
|
|
|
|
namespace Avalonia.Markup.Xaml.UnitTests.Data
|
|
|
{
|
|
|
public class BindingTests_Validation
|
|
|
{
|
|
|
- public class Data : INotifyPropertyChanged
|
|
|
+ [Fact]
|
|
|
+ public void Disabled_Validation_Should_Trigger_Validation_Change_On_Exception()
|
|
|
{
|
|
|
- private string mustbeNonEmpty;
|
|
|
-
|
|
|
- public string MustBeNonEmpty
|
|
|
+ var source = new ValidationTestModel { MustBePositive = 5 };
|
|
|
+ var target = new TestControl { DataContext = source };
|
|
|
+ var binding = new Binding
|
|
|
{
|
|
|
- get { return mustbeNonEmpty; }
|
|
|
- set
|
|
|
- {
|
|
|
- if (string.IsNullOrEmpty(value))
|
|
|
- {
|
|
|
- throw new ArgumentException(nameof(value));
|
|
|
- }
|
|
|
- mustbeNonEmpty = value;
|
|
|
- }
|
|
|
- }
|
|
|
+ Path = nameof(source.MustBePositive),
|
|
|
+ Mode = BindingMode.TwoWay,
|
|
|
|
|
|
- public event PropertyChangedEventHandler PropertyChanged;
|
|
|
+ // Even though EnableValidation = false, exception validation is enabled.
|
|
|
+ EnableValidation = false,
|
|
|
+ };
|
|
|
|
|
|
- private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
|
|
|
- {
|
|
|
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
- }
|
|
|
+ target.Bind(TestControl.ValidationTestProperty, binding);
|
|
|
+
|
|
|
+ target.ValidationTest = -5;
|
|
|
+
|
|
|
+ Assert.False(target.ValidationStatus.IsValid);
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
- public void Disabled_Validation_Should_Not_Trigger_Validation_Change_Direct()
|
|
|
+ public void Enabled_Validation_Should_Trigger_Validation_Change_On_Exception()
|
|
|
{
|
|
|
- var source = new Data { MustBeNonEmpty = "Test" };
|
|
|
- var target = new TextBlock { DataContext = source };
|
|
|
+ var source = new ValidationTestModel { MustBePositive = 5 };
|
|
|
+ var target = new TestControl { DataContext = source };
|
|
|
var binding = new Binding
|
|
|
{
|
|
|
- Path = nameof(source.MustBeNonEmpty),
|
|
|
- Mode = Avalonia.Data.BindingMode.TwoWay,
|
|
|
- ValidationMethods = Avalonia.Data.ValidationMethods.None
|
|
|
+ Path = nameof(source.MustBePositive),
|
|
|
+ Mode = BindingMode.TwoWay,
|
|
|
+ EnableValidation = true,
|
|
|
};
|
|
|
- target.Bind(TextBlock.TextProperty, binding);
|
|
|
-
|
|
|
- target.Text = "";
|
|
|
|
|
|
- Assert.True(target.ValidationStatus.IsValid);
|
|
|
+ target.Bind(TestControl.ValidationTestProperty, binding);
|
|
|
+
|
|
|
+ target.ValidationTest = -5;
|
|
|
+ Assert.False(target.ValidationStatus.IsValid);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
[Fact]
|
|
|
- public void Enabled_Validation_Should_Trigger_Validation_Change_Direct()
|
|
|
+ public void Passed_Validation_Should_Not_Add_Invalid_Pseudo_Class()
|
|
|
{
|
|
|
- var source = new Data { MustBeNonEmpty = "Test" };
|
|
|
- var target = new TextBlock { DataContext = source };
|
|
|
+ var control = new TestControl();
|
|
|
+ var model = new ValidationTestModel { MustBePositive = 1 };
|
|
|
var binding = new Binding
|
|
|
{
|
|
|
- Path = nameof(source.MustBeNonEmpty),
|
|
|
- Mode = Avalonia.Data.BindingMode.TwoWay,
|
|
|
- ValidationMethods = Avalonia.Data.ValidationMethods.All
|
|
|
+ Path = nameof(model.MustBePositive),
|
|
|
+ Mode = BindingMode.TwoWay,
|
|
|
+ EnableValidation = true,
|
|
|
};
|
|
|
- target.Bind(TextBlock.TextProperty, binding);
|
|
|
-
|
|
|
- target.Text = "";
|
|
|
- Assert.False(target.ValidationStatus.IsValid);
|
|
|
+
|
|
|
+ control.Bind(TestControl.ValidationTestProperty, binding);
|
|
|
+ control.DataContext = model;
|
|
|
+ Assert.DoesNotContain(control.Classes, x => x == ":invalid");
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
- public void Disabled_Validation_Should_Not_Trigger_Validation_Change_Styled()
|
|
|
+ public void Failed_Validation_Should_Add_Invalid_Pseudo_Class()
|
|
|
{
|
|
|
- var source = new Data { MustBeNonEmpty = "Test" };
|
|
|
- var target = new TextBlock { DataContext = source };
|
|
|
+ var control = new TestControl();
|
|
|
+ var model = new ValidationTestModel { MustBePositive = 1 };
|
|
|
var binding = new Binding
|
|
|
{
|
|
|
- Path = nameof(source.MustBeNonEmpty),
|
|
|
- Mode = Avalonia.Data.BindingMode.TwoWay,
|
|
|
- ValidationMethods = Avalonia.Data.ValidationMethods.None
|
|
|
+ Path = nameof(model.MustBePositive),
|
|
|
+ Mode = BindingMode.TwoWay,
|
|
|
+ EnableValidation = true,
|
|
|
};
|
|
|
- target.Bind(Control.TagProperty, binding);
|
|
|
-
|
|
|
- target.Tag = "";
|
|
|
|
|
|
- Assert.True(target.ValidationStatus.IsValid);
|
|
|
+ control.Bind(TestControl.ValidationTestProperty, binding);
|
|
|
+ control.DataContext = model;
|
|
|
+ control.ValidationTest = -5;
|
|
|
+ Assert.Contains(control.Classes, x => x == ":invalid");
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
- public void Enabled_Validation_Should_Trigger_Validation_Change_Styled()
|
|
|
+ public void Failed_Then_Passed_Validation_Should_Remove_Invalid_Pseudo_Class()
|
|
|
{
|
|
|
- var source = new Data { MustBeNonEmpty = "Test" };
|
|
|
- var target = new TextBlock { DataContext = source };
|
|
|
+ var control = new TestControl();
|
|
|
+ var model = new ValidationTestModel { MustBePositive = 1 };
|
|
|
+
|
|
|
var binding = new Binding
|
|
|
{
|
|
|
- Path = nameof(source.MustBeNonEmpty),
|
|
|
- Mode = Avalonia.Data.BindingMode.TwoWay,
|
|
|
- ValidationMethods = Avalonia.Data.ValidationMethods.All
|
|
|
+ Path = nameof(model.MustBePositive),
|
|
|
+ Mode = BindingMode.TwoWay,
|
|
|
+ EnableValidation = true,
|
|
|
};
|
|
|
- target.Bind(Control.TagProperty, binding);
|
|
|
|
|
|
- target.Tag = "";
|
|
|
- Assert.False(target.ValidationStatus.IsValid);
|
|
|
+ control.Bind(TestControl.ValidationTestProperty, binding);
|
|
|
+ control.DataContext = model;
|
|
|
+
|
|
|
+
|
|
|
+ control.ValidationTest = -5;
|
|
|
+ Assert.Contains(control.Classes, x => x == ":invalid");
|
|
|
+ control.ValidationTest = 5;
|
|
|
+ Assert.DoesNotContain(control.Classes, x => x == ":invalid");
|
|
|
+ }
|
|
|
+
|
|
|
+ private class TestControl : Control
|
|
|
+ {
|
|
|
+ public static readonly StyledProperty<int> ValidationTestProperty
|
|
|
+ = AvaloniaProperty.Register<TestControl, int>(nameof(ValidationTest), 1, defaultBindingMode: BindingMode.TwoWay);
|
|
|
+
|
|
|
+ public int ValidationTest
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ return GetValue(ValidationTestProperty);
|
|
|
+ }
|
|
|
+ set
|
|
|
+ {
|
|
|
+ SetValue(ValidationTestProperty, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void DataValidationChanged(AvaloniaProperty property, IValidationStatus status)
|
|
|
+ {
|
|
|
+ if (property == ValidationTestProperty)
|
|
|
+ {
|
|
|
+ UpdateValidationState(status);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private class ValidationTestModel
|
|
|
+ {
|
|
|
+ private int mustBePositive;
|
|
|
+
|
|
|
+ public int MustBePositive
|
|
|
+ {
|
|
|
+ get { return mustBePositive; }
|
|
|
+ set
|
|
|
+ {
|
|
|
+ if (value <= 0)
|
|
|
+ {
|
|
|
+ throw new ArgumentOutOfRangeException(nameof(value));
|
|
|
+ }
|
|
|
+ mustBePositive = value;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|