diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index b0858f8bc7..394e22eac1 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -469,6 +469,15 @@ 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 vistor, ref TData data)
+ where TData : struct;
+
///
/// Notifies the observable.
///
diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs
index d0dd841a70..d3b5277c53 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.Utilities;
#nullable enable
@@ -101,6 +102,12 @@ namespace Avalonia
return (DirectPropertyMetadata)base.GetMetadata(type);
}
+ ///
+ public override void Accept(IAvaloniaPropertyVisitor vistor, ref TData data)
+ {
+ vistor.Visit(this, ref data);
+ }
+
///
internal override void RouteClearValue(IAvaloniaObject o)
{
diff --git a/src/Avalonia.Base/StyledPropertyBase.cs b/src/Avalonia.Base/StyledPropertyBase.cs
index 53fcb51c5b..fb07ef3f62 100644
--- a/src/Avalonia.Base/StyledPropertyBase.cs
+++ b/src/Avalonia.Base/StyledPropertyBase.cs
@@ -5,6 +5,7 @@ using System;
using System.Diagnostics;
using Avalonia.Data;
using Avalonia.Reactive;
+using Avalonia.Utilities;
namespace Avalonia
{
@@ -169,6 +170,12 @@ namespace Avalonia
base.OverrideMetadata(type, metadata);
}
+ ///
+ public override void Accept(IAvaloniaPropertyVisitor vistor, ref TData data)
+ {
+ vistor.Visit(this, ref data);
+ }
+
///
/// Gets the string representation of the property.
///
diff --git a/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs b/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs
new file mode 100644
index 0000000000..4b889eb129
--- /dev/null
+++ b/src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs
@@ -0,0 +1,34 @@
+#nullable enable
+
+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/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs
index 788376b2fd..c7eebdd70a 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs
@@ -3,6 +3,7 @@
using System;
using Avalonia.Data;
+using Avalonia.Utilities;
using Xunit;
namespace Avalonia.Base.UnitTests
@@ -123,6 +124,11 @@ namespace Avalonia.Base.UnitTests
OverrideMetadata(typeof(T), metadata);
}
+ public override void Accept(IAvaloniaPropertyVisitor vistor, ref TData data)
+ {
+ throw new NotImplementedException();
+ }
+
internal override IDisposable RouteBind(
IAvaloniaObject o,
IObservable> source,