diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index bc1e95805f..1f14ddede4 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -646,10 +646,12 @@ namespace Avalonia
/// enabled.
///
/// The property.
- /// The new binding value for the property.
- protected virtual void UpdateDataValidation(
- AvaloniaProperty property,
- BindingValue value)
+ /// The current data binding state.
+ /// The current data binding error, if any.
+ protected virtual void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
}
@@ -860,7 +862,7 @@ namespace Avalonia
if (metadata.EnableDataValidation == true)
{
- UpdateDataValidation(property, value);
+ UpdateDataValidation(property, value.Type, value.Error);
}
}
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index 62ca971412..fd43ced196 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Avalonia.Data;
using Avalonia.Data.Core;
+using Avalonia.Styling;
using Avalonia.Utilities;
namespace Avalonia
@@ -454,15 +455,6 @@ namespace Avalonia
return Name;
}
- ///
- /// Uses the visitor pattern to resolve an untyped property to a typed property.
- ///
- /// The type of user data passed.
- /// The visitor which will accept the typed property.
- /// The user data to pass.
- public abstract void Accept(IAvaloniaPropertyVisitor visitor, ref TData data)
- where TData : struct;
-
///
/// Routes an untyped ClearValue call to a typed call.
///
@@ -508,6 +500,7 @@ namespace Avalonia
BindingPriority priority);
internal abstract void RouteInheritanceParentChanged(AvaloniaObject o, AvaloniaObject? oldParent);
+ internal abstract ISetterInstance CreateSetterInstance(IStyleable target, object? value);
///
/// Overrides the metadata for the property on the specified type.
diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs
index 6e3baea99b..9c1ffce24c 100644
--- a/src/Avalonia.Base/DirectPropertyBase.cs
+++ b/src/Avalonia.Base/DirectPropertyBase.cs
@@ -1,6 +1,7 @@
using System;
using Avalonia.Data;
using Avalonia.Reactive;
+using Avalonia.Styling;
using Avalonia.Utilities;
namespace Avalonia
@@ -120,12 +121,6 @@ namespace Avalonia
base.OverrideMetadata(type, metadata);
}
- ///
- public override void Accept(IAvaloniaPropertyVisitor visitor, ref TData data)
- {
- visitor.Visit(this, ref data);
- }
-
///
internal override void RouteClearValue(AvaloniaObject o)
{
@@ -181,5 +176,30 @@ namespace Avalonia
{
throw new NotSupportedException("Direct properties do not support inheritance.");
}
+
+ internal override ISetterInstance CreateSetterInstance(IStyleable target, object? value)
+ {
+ if (value is IBinding binding)
+ {
+ return new PropertySetterBindingInstance(
+ target,
+ this,
+ binding);
+ }
+ else if (value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(PropertyType))
+ {
+ return new PropertySetterLazyInstance(
+ target,
+ this,
+ () => (TValue)template.Build());
+ }
+ else
+ {
+ return new PropertySetterInstance(
+ target,
+ this,
+ (TValue)value!);
+ }
+ }
}
}
diff --git a/src/Avalonia.Base/Interactivity/IInteractive.cs b/src/Avalonia.Base/Interactivity/IInteractive.cs
index afda29e329..6d7dcd64f4 100644
--- a/src/Avalonia.Base/Interactivity/IInteractive.cs
+++ b/src/Avalonia.Base/Interactivity/IInteractive.cs
@@ -28,21 +28,6 @@ namespace Avalonia.Interactivity
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
bool handledEventsToo = false);
- ///
- /// Adds a handler for the specified routed event.
- ///
- /// The type of the event's args.
- /// The routed event.
- /// The handler.
- /// The routing strategies to listen to.
- /// Whether handled events should also be listened for.
- /// A disposable that terminates the event subscription.
- void AddHandler(
- RoutedEvent routedEvent,
- EventHandler handler,
- RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
- bool handledEventsToo = false) where TEventArgs : RoutedEventArgs;
-
///
/// Removes a handler for the specified routed event.
///
@@ -50,15 +35,6 @@ namespace Avalonia.Interactivity
/// The handler.
void RemoveHandler(RoutedEvent routedEvent, Delegate handler);
- ///
- /// Removes a handler for the specified routed event.
- ///
- /// The type of the event's args.
- /// The routed event.
- /// The handler.
- void RemoveHandler(RoutedEvent routedEvent, EventHandler handler)
- where TEventArgs : RoutedEventArgs;
-
///
/// Adds the object's handlers for a routed event to an event route.
///
diff --git a/src/Avalonia.Base/StyledPropertyBase.cs b/src/Avalonia.Base/StyledPropertyBase.cs
index f94723866a..dd5eb703ea 100644
--- a/src/Avalonia.Base/StyledPropertyBase.cs
+++ b/src/Avalonia.Base/StyledPropertyBase.cs
@@ -2,6 +2,7 @@ using System;
using System.Diagnostics;
using Avalonia.Data;
using Avalonia.Reactive;
+using Avalonia.Styling;
using Avalonia.Utilities;
namespace Avalonia
@@ -158,12 +159,6 @@ namespace Avalonia
base.OverrideMetadata(type, metadata);
}
- ///
- public override void Accept(IAvaloniaPropertyVisitor visitor, ref TData data)
- {
- visitor.Visit(this, ref data);
- }
-
///
/// Gets the string representation of the property.
///
@@ -237,6 +232,31 @@ namespace Avalonia
o.InheritanceParentChanged(this, oldParent);
}
+ internal override ISetterInstance CreateSetterInstance(IStyleable target, object? value)
+ {
+ if (value is IBinding binding)
+ {
+ return new PropertySetterBindingInstance(
+ target,
+ this,
+ binding);
+ }
+ else if (value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(PropertyType))
+ {
+ return new PropertySetterLazyInstance(
+ target,
+ this,
+ () => (TValue)template.Build());
+ }
+ else
+ {
+ return new PropertySetterInstance(
+ target,
+ this,
+ (TValue)value!);
+ }
+ }
+
private object? GetDefaultBoxedValue(Type type)
{
_ = type ?? throw new ArgumentNullException(nameof(type));
diff --git a/src/Avalonia.Base/Styling/Setter.cs b/src/Avalonia.Base/Styling/Setter.cs
index 168a882499..b4b3399022 100644
--- a/src/Avalonia.Base/Styling/Setter.cs
+++ b/src/Avalonia.Base/Styling/Setter.cs
@@ -16,7 +16,7 @@ namespace Avalonia.Styling
/// A is used to set a value on a
/// depending on a condition.
///
- public class Setter : ISetter, IAnimationSetter, IAvaloniaPropertyVisitor
+ public class Setter : ISetter, IAnimationSetter
{
private object? _value;
@@ -68,68 +68,7 @@ namespace Avalonia.Styling
throw new InvalidOperationException("Setter.Property must be set.");
}
- var data = new SetterVisitorData
- {
- target = target,
- value = Value,
- };
-
- Property.Accept(this, ref data);
- return data.result!;
- }
-
- void IAvaloniaPropertyVisitor.Visit(
- StyledPropertyBase property,
- ref SetterVisitorData data)
- {
- if (data.value is IBinding binding)
- {
- data.result = new PropertySetterBindingInstance(
- data.target,
- property,
- binding);
- }
- else if (data.value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(property.PropertyType))
- {
- data.result = new PropertySetterLazyInstance(
- data.target,
- property,
- () => (T)template.Build());
- }
- else
- {
- data.result = new PropertySetterInstance(
- data.target,
- property,
- (T)data.value!);
- }
- }
-
- void IAvaloniaPropertyVisitor.Visit(
- DirectPropertyBase property,
- ref SetterVisitorData data)
- {
- if (data.value is IBinding binding)
- {
- data.result = new PropertySetterBindingInstance(
- data.target,
- property,
- binding);
- }
- else if (data.value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(property.PropertyType))
- {
- data.result = new PropertySetterLazyInstance(
- data.target,
- property,
- () => (T)template.Build());
- }
- else
- {
- data.result = new PropertySetterInstance(
- data.target,
- property,
- (T)data.value!);
- }
+ return Property.CreateSetterInstance(target, Value);
}
private struct SetterVisitorData
diff --git a/src/Avalonia.Base/Threading/IDispatcher.cs b/src/Avalonia.Base/Threading/IDispatcher.cs
index eccd42bd4e..713a7ac4d7 100644
--- a/src/Avalonia.Base/Threading/IDispatcher.cs
+++ b/src/Avalonia.Base/Threading/IDispatcher.cs
@@ -26,15 +26,6 @@ namespace Avalonia.Threading
/// The priority with which to invoke the method.
void Post(Action action, DispatcherPriority priority = default);
- ///
- /// Posts an action that will be invoked on the dispatcher thread.
- ///
- /// type of argument
- /// The method to call.
- /// The argument of method to call.
- /// The priority with which to invoke the method.
- void Post(Action action, T arg, DispatcherPriority priority = default);
-
///
/// Invokes a action on the dispatcher thread.
///
@@ -43,14 +34,6 @@ namespace Avalonia.Threading
/// A task that can be used to track the method's execution.
Task InvokeAsync(Action action, DispatcherPriority priority = default);
- ///
- /// Invokes a method on the dispatcher thread.
- ///
- /// The method.
- /// The priority with which to invoke the method.
- /// A task that can be used to track the method's execution.
- Task InvokeAsync(Func function, DispatcherPriority priority = default);
-
///
/// Queues the specified work to run on the dispatcher thread and returns a proxy for the
/// task returned by .
@@ -59,14 +42,5 @@ namespace Avalonia.Threading
/// The priority with which to invoke the method.
/// A task that represents a proxy for the task returned by .
Task InvokeAsync(Func function, DispatcherPriority priority = default);
-
- ///
- /// Queues the specified work to run on the dispatcher thread and returns a proxy for the
- /// task returned by .
- ///
- /// The work to execute asynchronously.
- /// The priority with which to invoke the method.
- /// A task that represents a proxy for the task returned by .
- Task InvokeAsync(Func> function, DispatcherPriority priority = default);
}
}
diff --git a/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs b/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs
deleted file mode 100644
index 6a8df91b81..0000000000
--- a/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace Avalonia.Utilities
-{
- ///
- /// A visitor to resolve an untyped to a typed property.
- ///
- /// The type of user data passed.
- ///
- /// Pass an instance that implements this interface to
- ///
- /// in order to resolve un untyped to a typed
- /// or .
- ///
- public interface IAvaloniaPropertyVisitor
- where TData : struct
- {
- ///
- /// Called when the property is a styled property.
- ///
- /// The property value type.
- /// The property.
- /// The user data.
- void Visit(StyledPropertyBase property, ref TData data);
-
- ///
- /// Called when the property is a direct property.
- ///
- /// The property value type.
- /// The property.
- /// The user data.
- void Visit(DirectPropertyBase property, ref TData data);
- }
-}
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index 3316c06bf5..5c95932c1f 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -1346,12 +1346,16 @@ namespace Avalonia.Controls
/// enabled.
///
/// The property.
- /// The new binding value for the property.
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ /// The current data binding state.
+ /// The current data binding error, if any.
+ protected override void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
if (property == TextProperty || property == SelectedItemProperty)
{
- DataValidationErrors.SetError(this, value.Error);
+ DataValidationErrors.SetError(this, error);
}
}
diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index a4a147e0f3..0ef1ba4c8c 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -498,12 +498,15 @@ namespace Avalonia.Controls
protected override AutomationPeer OnCreateAutomationPeer() => new ButtonAutomationPeer(this);
///
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ protected override void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
- base.UpdateDataValidation(property, value);
+ base.UpdateDataValidation(property, state, error);
if (property == CommandProperty)
{
- if (value.Type == BindingValueType.BindingError)
+ if (state == BindingValueType.BindingError)
{
if (_commandCanExecute)
{
diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
index 0ac2056ed1..0409eb30aa 100644
--- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
+++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
@@ -540,11 +540,11 @@ namespace Avalonia.Controls
}
}
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error)
{
if (property == SelectedDateProperty)
{
- DataValidationErrors.SetError(this, value.Error);
+ DataValidationErrors.SetError(this, error);
}
}
diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs
index 955af8888b..619eafb71b 100644
--- a/src/Avalonia.Controls/MenuItem.cs
+++ b/src/Avalonia.Controls/MenuItem.cs
@@ -501,12 +501,15 @@ namespace Avalonia.Controls
return new MenuItemAutomationPeer(this);
}
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ protected override void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
- base.UpdateDataValidation(property, value);
+ base.UpdateDataValidation(property, state, error);
if (property == CommandProperty)
{
- _commandBindingError = value.Type == BindingValueType.BindingError;
+ _commandBindingError = state == BindingValueType.BindingError;
if (_commandBindingError && _commandCanExecute)
{
_commandCanExecute = false;
diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
index fbbaab6182..4d86a0f17c 100644
--- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
+++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
@@ -403,12 +403,16 @@ namespace Avalonia.Controls
/// enabled.
///
/// The property.
- /// The new binding value for the property.
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ /// The current data binding state.
+ /// The current data binding error, if any.
+ protected override void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
if (property == TextProperty || property == ValueProperty)
{
- DataValidationErrors.SetError(this, value.Error);
+ DataValidationErrors.SetError(this, error);
}
}
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 6f2554bef3..bff6799792 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -501,12 +501,16 @@ namespace Avalonia.Controls.Primitives
/// enabled.
///
/// The property.
- /// The new binding value for the property.
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ /// The current data binding state.
+ /// The current data binding error, if any.
+ protected override void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
if (property == SelectedItemProperty)
{
- DataValidationErrors.SetError(this, value.Error);
+ DataValidationErrors.SetError(this, error);
}
}
diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs
index f0a0fba1af..64dfce22d4 100644
--- a/src/Avalonia.Controls/Slider.cs
+++ b/src/Avalonia.Controls/Slider.cs
@@ -361,11 +361,14 @@ namespace Avalonia.Controls
Value = IsSnapToTickEnabled ? SnapToTick(finalValue) : finalValue;
}
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ protected override void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
if (property == ValueProperty)
{
- DataValidationErrors.SetError(this, value.Error);
+ DataValidationErrors.SetError(this, error);
}
}
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index 1f3dbc87db..0be58e7fcc 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -1262,11 +1262,14 @@ namespace Avalonia.Controls
return new TextBoxAutomationPeer(this);
}
- protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ protected override void UpdateDataValidation(
+ AvaloniaProperty property,
+ BindingValueType state,
+ Exception? error)
{
if (property == TextProperty)
{
- DataValidationErrors.SetError(this, value.Error);
+ DataValidationErrors.SetError(this, error);
}
}
diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs
index 1d806913dd..b2a188a2ea 100644
--- a/src/Avalonia.Controls/TreeView.cs
+++ b/src/Avalonia.Controls/TreeView.cs
@@ -401,7 +401,7 @@ namespace Avalonia.Controls
protected virtual ITreeItemContainerGenerator CreateTreeItemContainerGenerator() =>
CreateTreeItemContainerGenerator();
- protected virtual ITreeItemContainerGenerator CreateTreeItemContainerGenerator() where TVItem: TreeViewItem, new()
+ protected ITreeItemContainerGenerator CreateTreeItemContainerGenerator() where TVItem: TreeViewItem, new()
{
return new TreeItemContainerGenerator(
this,
diff --git a/src/Avalonia.Controls/TreeViewItem.cs b/src/Avalonia.Controls/TreeViewItem.cs
index a0a3c09942..490b0b3ce3 100644
--- a/src/Avalonia.Controls/TreeViewItem.cs
+++ b/src/Avalonia.Controls/TreeViewItem.cs
@@ -96,7 +96,7 @@ namespace Avalonia.Controls
protected override IItemContainerGenerator CreateItemContainerGenerator() => CreateTreeItemContainerGenerator();
///
- protected virtual ITreeItemContainerGenerator CreateTreeItemContainerGenerator()
+ protected ITreeItemContainerGenerator CreateTreeItemContainerGenerator()
where TVItem: TreeViewItem, new()
{
return new TreeItemContainerGenerator(
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs
index 65f03b3eca..d48e58136a 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_DataValidation.cs
@@ -52,14 +52,14 @@ namespace Avalonia.Base.UnitTests
source.OnNext(BindingValue.DataValidationError(new Exception()));
source.OnNext(7);
- var result = target.Notifications.Cast>().ToList();
+ var result = target.Notifications;
Assert.Equal(4, result.Count);
- Assert.Equal(BindingValueType.Value, result[0].Type);
- Assert.Equal(6, result[0].Value);
- Assert.Equal(BindingValueType.BindingError, result[1].Type);
- Assert.Equal(BindingValueType.DataValidationError, result[2].Type);
- Assert.Equal(BindingValueType.Value, result[3].Type);
- Assert.Equal(7, result[3].Value);
+ Assert.Equal(BindingValueType.Value, result[0].type);
+ Assert.Equal(6, result[0].value);
+ Assert.Equal(BindingValueType.BindingError, result[1].type);
+ Assert.Equal(BindingValueType.DataValidationError, result[2].type);
+ Assert.Equal(BindingValueType.Value, result[3].type);
+ Assert.Equal(7, result[3].value);
}
[Fact]
@@ -72,8 +72,7 @@ namespace Avalonia.Base.UnitTests
target.Bind(Class1.NonValidatedDirectProperty, source);
source.OnNext(1);
- var result = target.Notifications.Cast>().ToList();
- Assert.Equal(1, result.Count);
+ Assert.Equal(1, target.Notifications.Count);
}
[Fact]
@@ -154,13 +153,14 @@ namespace Avalonia.Base.UnitTests
set { SetAndRaise(ValidatedDirectStringProperty, ref _directString, value); }
}
- public IList