diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs index 2751d8d5d5..4041573f8f 100644 --- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs +++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs @@ -216,7 +216,11 @@ namespace Avalonia Contract.Requires(property != null); Contract.Requires(binding != null); - var result = binding.Initiate(target, property, anchor); + var result = binding.Initiate( + target, + property, + anchor, + property.GetMetadata(target.GetType()).EnabledDataValidation); if (result != null) { @@ -311,7 +315,8 @@ namespace Avalonia public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, - object anchor = null) + object anchor = null, + bool enableDataValidation = false) { return new InstancedBinding(_source); } diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs index 6374042aab..f12c534aa8 100644 --- a/src/Avalonia.Base/AvaloniaProperty.cs +++ b/src/Avalonia.Base/AvaloniaProperty.cs @@ -275,7 +275,8 @@ namespace Avalonia var metadata = new StyledPropertyMetadata( defaultValue, validate: Cast(validate), - defaultBindingMode: defaultBindingMode); + defaultBindingMode: defaultBindingMode, + enableDataValidation: enableDataValidation); var result = new StyledProperty( name, @@ -316,7 +317,8 @@ namespace Avalonia var metadata = new StyledPropertyMetadata( defaultValue, validate: Cast(validate), - defaultBindingMode: defaultBindingMode); + defaultBindingMode: defaultBindingMode, + enableDataValidation: enableDataValidation); var result = new AttachedProperty(name, typeof(TOwner), metadata, inherits); AvaloniaPropertyRegistry.Instance.Register(typeof(THost), result); @@ -353,7 +355,8 @@ namespace Avalonia var metadata = new StyledPropertyMetadata( defaultValue, validate: Cast(validate), - defaultBindingMode: defaultBindingMode); + defaultBindingMode: defaultBindingMode, + enableDataValidation: enableDataValidation); var result = new AttachedProperty(name, ownerType, metadata, inherits); AvaloniaPropertyRegistry.Instance.Register(typeof(THost), result); @@ -389,7 +392,8 @@ namespace Avalonia var metadata = new DirectPropertyMetadata( unsetValue: unsetValue, - defaultBindingMode: defaultBindingMode); + defaultBindingMode: defaultBindingMode, + enableDataValidation: enableDataValidation); var result = new DirectProperty(name, getter, setter, metadata); AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result); diff --git a/src/Avalonia.Base/Data/IBinding.cs b/src/Avalonia.Base/Data/IBinding.cs index 88c20dd288..70447ad3eb 100644 --- a/src/Avalonia.Base/Data/IBinding.cs +++ b/src/Avalonia.Base/Data/IBinding.cs @@ -19,12 +19,14 @@ namespace Avalonia.Data /// order to locate named controls or resources. The parameter /// can be used to provice this context. /// + /// Whether data validation should be enabled. /// /// A or null if the binding could not be resolved. /// InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, - object anchor = null); + object anchor = null, + bool enableDataValidation = false); } } diff --git a/src/Avalonia.Base/Data/IndexerBinding.cs b/src/Avalonia.Base/Data/IndexerBinding.cs index b2d38920d0..729b21b0d9 100644 --- a/src/Avalonia.Base/Data/IndexerBinding.cs +++ b/src/Avalonia.Base/Data/IndexerBinding.cs @@ -21,7 +21,11 @@ namespace Avalonia.Data public AvaloniaProperty Property { get; } private BindingMode Mode { get; } - public InstancedBinding Initiate(IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null) + public InstancedBinding Initiate( + IAvaloniaObject target, + AvaloniaProperty targetProperty, + object anchor = null, + bool enableDataValidation = false) { var mode = Mode == BindingMode.Default ? targetProperty.GetMetadata(target.GetType()).DefaultBindingMode : diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs index 55f2baf04e..9c6556b809 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs @@ -78,16 +78,12 @@ namespace Avalonia.Markup.Xaml.Data /// public object Source { get; set; } - /// - /// Gets or sets a value indicating whether the property should be validated. - /// - public bool EnableValidation { get; set; } - /// public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, - object anchor = null) + object anchor = null, + bool enableDataValidation = false) { Contract.Requires(target != null); @@ -105,7 +101,7 @@ namespace Avalonia.Markup.Xaml.Data } else if (Source != null) { - observer = CreateSourceObserver(Source, pathInfo.Path); + observer = CreateSourceObserver(Source, pathInfo.Path, enableDataValidation); } else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext) { @@ -113,7 +109,8 @@ namespace Avalonia.Markup.Xaml.Data target, pathInfo.Path, targetProperty == Control.DataContextProperty, - anchor); + anchor, + enableDataValidation); } else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) { @@ -197,7 +194,8 @@ namespace Avalonia.Markup.Xaml.Data IAvaloniaObject target, string path, bool targetIsDataContext, - object anchor) + object anchor, + bool enableDataValidation) { Contract.Requires(target != null); @@ -220,7 +218,7 @@ namespace Avalonia.Markup.Xaml.Data () => target.GetValue(Control.DataContextProperty), path, update, - EnableValidation); + enableDataValidation); return result; } @@ -229,7 +227,7 @@ namespace Avalonia.Markup.Xaml.Data return new ExpressionObserver( GetParentDataContext(target), path, - EnableValidation); + enableDataValidation); } } @@ -240,15 +238,18 @@ namespace Avalonia.Markup.Xaml.Data var result = new ExpressionObserver( ControlLocator.Track(target, elementName), path, - EnableValidation); + false); return result; } - private ExpressionObserver CreateSourceObserver(object source, string path) + private ExpressionObserver CreateSourceObserver( + object source, + string path, + bool enabledDataValidation) { Contract.Requires(source != null); - return new ExpressionObserver(source, path, EnableValidation); + return new ExpressionObserver(source, path, enabledDataValidation); } private ExpressionObserver CreateTemplatedParentObserver( diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs index 91a502a44f..69190be220 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs @@ -53,7 +53,8 @@ namespace Avalonia.Markup.Xaml.Data public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, - object anchor = null) + object anchor = null, + bool enableDataValidation = false) { if (Converter == null) { diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs index 442f9199e8..c538c0768e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs @@ -37,7 +37,8 @@ namespace Avalonia.Markup.Xaml.Data public InstancedBinding Initiate( IAvaloniaObject target, AvaloniaProperty targetProperty, - object anchor = null) + object anchor = null, + bool enableDataValidation = false) { if (Name == "Red") { diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs index 70d3f7d161..b131f07fd4 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs @@ -29,7 +29,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions Mode = Mode, Path = Path, Priority = Priority, - EnableValidation = EnableValidation, }; } @@ -41,6 +40,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public string Path { get; set; } public BindingPriority Priority { get; set; } = BindingPriority.LocalValue; public object Source { get; set; } - public bool EnableValidation { get; set; } } } \ No newline at end of file diff --git a/tests/Avalonia.Controls.UnitTests/TextBoxTests_ValidationState.cs b/tests/Avalonia.Controls.UnitTests/TextBoxTests_ValidationState.cs index 1036b70d30..34de11cc3b 100644 --- a/tests/Avalonia.Controls.UnitTests/TextBoxTests_ValidationState.cs +++ b/tests/Avalonia.Controls.UnitTests/TextBoxTests_ValidationState.cs @@ -21,7 +21,7 @@ namespace Avalonia.Controls.UnitTests var target = new TextBox(); var binding = new Binding(nameof(ExceptionTest.LessThan10)); binding.Source = new ExceptionTest(); - binding.EnableValidation = true; + ////binding.EnableValidation = true; target.Bind(TextBox.TextProperty, binding); Assert.True(false); @@ -41,7 +41,7 @@ namespace Avalonia.Controls.UnitTests var target = new TextBox(); var binding = new Binding(nameof(ExceptionTest.LessThan10)); binding.Source = new ExceptionTest(); - binding.EnableValidation = true; + ////binding.EnableValidation = true; target.Bind(TextBox.TextProperty, binding); Assert.True(false); @@ -61,7 +61,7 @@ namespace Avalonia.Controls.UnitTests var target = new TextBox(); var binding = new Binding(nameof(ExceptionTest.LessThan10)); binding.Source = new IndeiTest(); - binding.EnableValidation = true; + ////binding.EnableValidation = true; target.Bind(TextBox.TextProperty, binding); Assert.True(false); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Validation.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Validation.cs index 835e65d9e5..f128a67839 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Validation.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Validation.cs @@ -25,15 +25,15 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data } [Fact] - public void Validated_Property_Does_Not_Receive_BindingNotifications() + public void Validated_Property_Receives_BindingNotifications() { var source = new ValidationTestModel { MustBePositive = 5 }; var target = new TestControl { DataContext = source, - [!TestControl.ValidatedProperty] = new Binding(nameof(source.MustBePositive)), }; + target.Bind(TestControl.ValidatedProperty, new Binding(nameof(source.MustBePositive))); source.MustBePositive = 6; Assert.Equal( diff --git a/tests/Avalonia.Styling.UnitTests/SetterTests.cs b/tests/Avalonia.Styling.UnitTests/SetterTests.cs index 4de90b7790..84536fa47b 100644 --- a/tests/Avalonia.Styling.UnitTests/SetterTests.cs +++ b/tests/Avalonia.Styling.UnitTests/SetterTests.cs @@ -27,7 +27,7 @@ namespace Avalonia.Styling.UnitTests var control = new TextBlock(); var subject = new BehaviorSubject("foo"); var descriptor = new InstancedBinding(subject); - var binding = Mock.Of(x => x.Initiate(control, TextBlock.TextProperty, null) == descriptor); + var binding = Mock.Of(x => x.Initiate(control, TextBlock.TextProperty, null, false) == descriptor); var style = Mock.Of(); var setter = new Setter(TextBlock.TextProperty, binding);