Browse Source

Added untyped SetCurrentValue.

pull/10324/head
Steven Kirk 4 years ago
parent
commit
0ce9180d7c
  1. 34
      src/Avalonia.Base/AvaloniaObject.cs
  2. 7
      src/Avalonia.Base/AvaloniaProperty.cs
  3. 5
      src/Avalonia.Base/DirectPropertyBase.cs
  4. 21
      src/Avalonia.Base/StyledProperty.cs
  5. 26
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetCurrentValue.cs
  6. 5
      tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs

34
src/Avalonia.Base/AvaloniaObject.cs

@ -355,6 +355,40 @@ namespace Avalonia
SetDirectValueUnchecked(property, value);
}
/// <summary>
/// Sets the value of a dependency property without changing its value source.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <remarks>
/// This method is used by a component that programmatically sets the value of one of its
/// own properties without disabling an application's declared use of the property. The
/// method changes the effective value of the property, but existing data bindings and
/// styles will continue to work.
///
/// The new value will have the property's current <see cref="BindingPriority"/>, even if
/// that priority is <see cref="BindingPriority.Unset"/> or
/// <see cref="BindingPriority.Inherited"/>.
/// </remarks>
public void SetCurrentValue(AvaloniaProperty property, object? value) =>
property.RouteSetCurrentValue(this, value);
/// <summary>
/// Sets the value of a dependency property without changing its value source.
/// </summary>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <remarks>
/// This method is used by a component that programmatically sets the value of one of its
/// own properties without disabling an application's declared use of the property. The
/// method changes the effective value of the property, but existing data bindings and
/// styles will continue to work.
///
/// The new value will have the property's current <see cref="BindingPriority"/>, even if
/// that priority is <see cref="BindingPriority.Unset"/> or
/// <see cref="BindingPriority.Inherited"/>.
/// </remarks>
public void SetCurrentValue<T>(StyledProperty<T> property, T value)
{
_ = property ?? throw new ArgumentNullException(nameof(property));

7
src/Avalonia.Base/AvaloniaProperty.cs

@ -496,6 +496,13 @@ namespace Avalonia
object? value,
BindingPriority priority);
/// <summary>
/// Routes an untyped SetCurrentValue call to a typed call.
/// </summary>
/// <param name="o">The object instance.</param>
/// <param name="value">The value.</param>
internal abstract void RouteSetCurrentValue(AvaloniaObject o, object? value);
/// <summary>
/// Routes an untyped Bind call to a typed call.
/// </summary>

5
src/Avalonia.Base/DirectPropertyBase.cs

@ -152,6 +152,11 @@ namespace Avalonia
return null;
}
internal override void RouteSetCurrentValue(AvaloniaObject o, object? value)
{
RouteSetValue(o, value, BindingPriority.LocalValue);
}
/// <summary>
/// Routes an untyped Bind call to a typed call.
/// </summary>

21
src/Avalonia.Base/StyledProperty.cs

@ -220,6 +220,27 @@ namespace Avalonia
}
}
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
internal override void RouteSetCurrentValue(AvaloniaObject target, object? value)
{
if (value == BindingOperations.DoNothing)
return;
if (value == UnsetValue)
{
target.ClearValue(this);
}
else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var converted))
{
target.SetCurrentValue<TValue>(this, (TValue)converted!);
}
else
{
var type = value?.GetType().FullName ?? "(null)";
throw new ArgumentException($"Invalid value for Property '{Name}': '{value}' ({type})");
}
}
internal override IDisposable RouteBind(
AvaloniaObject target,
IObservable<object?> source,

26
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetCurrentValue.cs

@ -21,6 +21,19 @@ namespace Avalonia.Base.UnitTests
Assert.True(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void SetCurrentValue_Sets_Unset_Value_Untyped()
{
var target = new Class1();
target.SetCurrentValue((AvaloniaProperty)Class1.FooProperty, "newvalue");
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty));
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(BindingPriority.Unset, GetPriority(target, Class1.FooProperty));
Assert.True(IsOverridden(target, Class1.FooProperty));
}
[Theory]
[InlineData(BindingPriority.LocalValue)]
[InlineData(BindingPriority.Style)]
@ -140,6 +153,19 @@ namespace Avalonia.Base.UnitTests
Assert.Equal(60, target.GetValue(Class1.CoercedProperty));
}
[Fact]
public void SetCurrentValue_Unset_Clears_CurrentValue()
{
var target = new Class1();
target.SetCurrentValue(Class1.FooProperty, "newvalue");
target.SetCurrentValue(Class1.FooProperty, AvaloniaProperty.UnsetValue);
Assert.Equal("foodefault", target.Foo);
Assert.False(target.IsSet(Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Theory]
[InlineData(BindingPriority.LocalValue)]
[InlineData(BindingPriority.Style)]

5
tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs

@ -179,6 +179,11 @@ namespace Avalonia.Base.UnitTests
throw new NotImplementedException();
}
internal override void RouteSetCurrentValue(AvaloniaObject o, object value)
{
throw new NotImplementedException();
}
internal override EffectiveValue CreateEffectiveValue(AvaloniaObject o)
{
throw new NotImplementedException();

Loading…
Cancel
Save