diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index b0ff591682..88b99cd99a 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -311,7 +311,10 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- public void SetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ public IDisposable SetValue(
StyledPropertyBase property,
T value,
BindingPriority priority = BindingPriority.LocalValue)
@@ -335,8 +338,10 @@ namespace Avalonia
}
else if (!(value is DoNothingType))
{
- Values.SetValue(property, value, priority);
+ return Values.SetValue(property, value, priority);
}
+
+ return null;
}
///
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index a4c7fa95a5..0f82042dcd 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -458,7 +458,10 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- public static void SetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ public static IDisposable SetValue(
this IAvaloniaObject target,
AvaloniaProperty property,
object value,
@@ -467,7 +470,7 @@ namespace Avalonia
target = target ?? throw new ArgumentNullException(nameof(target));
property = property ?? throw new ArgumentNullException(nameof(property));
- property.RouteSetValue(target, value, priority);
+ return property.RouteSetValue(target, value, priority);
}
///
@@ -478,7 +481,10 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- public static void SetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ public static IDisposable SetValue(
this IAvaloniaObject target,
AvaloniaProperty property,
T value,
@@ -490,11 +496,10 @@ namespace Avalonia
switch (property)
{
case StyledPropertyBase styled:
- target.SetValue(styled, value, priority);
- break;
+ return target.SetValue(styled, value, priority);
case DirectPropertyBase direct:
target.SetValue(direct, value);
- break;
+ return null;
default:
throw new NotSupportedException("Unsupported AvaloniaProperty type.");
}
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index aa7a675764..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.
///
@@ -496,7 +505,10 @@ namespace Avalonia
/// The object instance.
/// The value.
/// The priority.
- internal abstract void RouteSetValue(
+ ///
+ /// An if setting the property can be undone, otherwise null.
+ ///
+ internal abstract IDisposable? RouteSetValue(
IAvaloniaObject o,
object value,
BindingPriority priority);
diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs
index 39ed3b084f..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)
{
@@ -114,7 +121,7 @@ namespace Avalonia
}
///
- internal override void RouteSetValue(
+ internal override IDisposable? RouteSetValue(
IAvaloniaObject o,
object value,
BindingPriority priority)
@@ -133,6 +140,8 @@ namespace Avalonia
{
throw v.Error!;
}
+
+ return null;
}
///
diff --git a/src/Avalonia.Base/IAvaloniaObject.cs b/src/Avalonia.Base/IAvaloniaObject.cs
index fb85ae222c..81a212b087 100644
--- a/src/Avalonia.Base/IAvaloniaObject.cs
+++ b/src/Avalonia.Base/IAvaloniaObject.cs
@@ -65,7 +65,7 @@ namespace Avalonia
/// The property.
/// The value.
/// The priority of the value.
- void SetValue(
+ IDisposable SetValue(
StyledPropertyBase property,
T value,
BindingPriority priority = BindingPriority.LocalValue);
diff --git a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs
index f15f56e32b..aa054c46ff 100644
--- a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs
@@ -10,16 +10,20 @@ namespace Avalonia.PropertyStore
/// .
///
/// The property type.
- internal class ConstantValueEntry : IPriorityValueEntry
+ internal class ConstantValueEntry : IPriorityValueEntry, IDisposable
{
+ private IValueSink _sink;
+
public ConstantValueEntry(
StyledPropertyBase property,
T value,
- BindingPriority priority)
+ BindingPriority priority,
+ IValueSink sink)
{
Property = property;
Value = value;
Priority = priority;
+ _sink = sink;
}
public StyledPropertyBase Property { get; }
@@ -28,6 +32,7 @@ namespace Avalonia.PropertyStore
Optional