Browse Source

Merge pull request #10324 from AvaloniaUI/feature/setcurrentvalue

Added `SetCurrentValue`
pull/10341/head
Max Katz 3 years ago
committed by GitHub
parent
commit
6c15bcde7a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 60
      src/Avalonia.Base/AvaloniaObject.cs
  2. 7
      src/Avalonia.Base/AvaloniaProperty.cs
  3. 23
      src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs
  4. 5
      src/Avalonia.Base/DirectPropertyBase.cs
  5. 6
      src/Avalonia.Base/PropertyStore/EffectiveValue.cs
  6. 29
      src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs
  7. 34
      src/Avalonia.Base/PropertyStore/ValueStore.cs
  8. 44
      src/Avalonia.Base/StyledProperty.cs
  9. 308
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetCurrentValue.cs
  10. 5
      tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs

60
src/Avalonia.Base/AvaloniaObject.cs

@ -118,7 +118,7 @@ namespace Avalonia
{
_ = property ?? throw new ArgumentNullException(nameof(property));
VerifyAccess();
_values.ClearLocalValue(property);
_values.ClearValue(property);
}
/// <summary>
@ -152,7 +152,7 @@ namespace Avalonia
property = property ?? throw new ArgumentNullException(nameof(property));
VerifyAccess();
_values.ClearLocalValue(property);
_values.ClearValue(property);
}
/// <summary>
@ -329,7 +329,7 @@ namespace Avalonia
if (value is UnsetValueType)
{
if (priority == BindingPriority.LocalValue)
_values.ClearLocalValue(property);
_values.ClearValue(property);
}
else if (value is not DoNothingType)
{
@ -355,6 +355,57 @@ 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));
VerifyAccess();
LogPropertySet(property, value, BindingPriority.LocalValue);
if (value is UnsetValueType)
{
_values.ClearValue(property);
}
else if (value is not DoNothingType)
{
_values.SetCurrentValue(property, value);
}
}
/// <summary>
/// Binds a <see cref="AvaloniaProperty"/> to an observable.
/// </summary>
@ -547,7 +598,8 @@ namespace Avalonia
property,
GetValue(property),
BindingPriority.LocalValue,
null);
null,
false);
}
return _values.GetDiagnostic(property);

7
src/Avalonia.Base/AvaloniaProperty.cs

@ -523,6 +523,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>

23
src/Avalonia.Base/Diagnostics/AvaloniaPropertyValue.cs

@ -3,28 +3,23 @@ using Avalonia.Data;
namespace Avalonia.Diagnostics
{
/// <summary>
/// Holds diagnostic-related information about the value of a <see cref="AvaloniaProperty"/>
/// on a <see cref="AvaloniaObject"/>.
/// Holds diagnostic-related information about the value of an <see cref="AvaloniaProperty"/>
/// on an <see cref="AvaloniaObject"/>.
/// </summary>
public class AvaloniaPropertyValue
{
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaPropertyValue"/> class.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The current property value.</param>
/// <param name="priority">The priority of the current value.</param>
/// <param name="diagnostic">A diagnostic string.</param>
public AvaloniaPropertyValue(
internal AvaloniaPropertyValue(
AvaloniaProperty property,
object? value,
BindingPriority priority,
string? diagnostic)
string? diagnostic,
bool isOverriddenCurrentValue)
{
Property = property;
Value = value;
Priority = priority;
Diagnostic = diagnostic;
IsOverriddenCurrentValue = isOverriddenCurrentValue;
}
/// <summary>
@ -46,5 +41,11 @@ namespace Avalonia.Diagnostics
/// Gets a diagnostic string.
/// </summary>
public string? Diagnostic { get; }
/// <summary>
/// Gets a value indicating whether the <see cref="Value"/> was overridden by a call to
/// <see cref="AvaloniaObject.SetCurrentValue{T}"/>.
/// </summary>
public bool IsOverriddenCurrentValue { get; }
}
}

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>

6
src/Avalonia.Base/PropertyStore/EffectiveValue.cs

@ -29,6 +29,12 @@ namespace Avalonia.PropertyStore
/// </summary>
public BindingPriority BasePriority { get; protected set; }
/// <summary>
/// Gets a value indicating whether the <see cref="Value"/> was overridden by a call to
/// <see cref="AvaloniaObject.SetCurrentValue{T}"/>.
/// </summary>
public bool IsOverridenCurrentValue { get; set; }
/// <summary>
/// Begins a reevaluation pass on the effective value.
/// </summary>

29
src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs

@ -57,7 +57,7 @@ namespace Avalonia.PropertyStore
Debug.Assert(priority != BindingPriority.LocalValue);
UpdateValueEntry(value, priority);
SetAndRaiseCore(owner, (StyledProperty<T>)value.Property, GetValue(value), priority);
SetAndRaiseCore(owner, (StyledProperty<T>)value.Property, GetValue(value), priority, false);
}
public void SetLocalValueAndRaise(
@ -65,7 +65,16 @@ namespace Avalonia.PropertyStore
StyledProperty<T> property,
T value)
{
SetAndRaiseCore(owner, property, value, BindingPriority.LocalValue);
SetAndRaiseCore(owner, property, value, BindingPriority.LocalValue, false);
}
public void SetCurrentValueAndRaise(
ValueStore owner,
StyledProperty<T> property,
T value)
{
IsOverridenCurrentValue = true;
SetAndRaiseCore(owner, property, value, Priority, true);
}
public bool TryGetBaseValue([MaybeNullWhen(false)] out T value)
@ -98,7 +107,7 @@ namespace Avalonia.PropertyStore
Debug.Assert(Priority != BindingPriority.Animation);
Debug.Assert(BasePriority != BindingPriority.Unset);
UpdateValueEntry(null, BindingPriority.Animation);
SetAndRaiseCore(owner, (StyledProperty<T>)property, _baseValue!, BasePriority);
SetAndRaiseCore(owner, (StyledProperty<T>)property, _baseValue!, BasePriority, false);
}
public override void CoerceValue(ValueStore owner, AvaloniaProperty property)
@ -158,15 +167,16 @@ namespace Avalonia.PropertyStore
ValueStore owner,
StyledProperty<T> property,
T value,
BindingPriority priority)
BindingPriority priority,
bool isOverriddenCurrentValue)
{
Debug.Assert(priority < BindingPriority.Inherited);
var oldValue = Value;
var valueChanged = false;
var baseValueChanged = false;
var v = value;
IsOverridenCurrentValue = isOverriddenCurrentValue;
if (_uncommon?._coerce is { } coerce)
v = coerce(owner.Owner, value);
@ -209,7 +219,6 @@ namespace Avalonia.PropertyStore
T baseValue,
BindingPriority basePriority)
{
Debug.Assert(priority < BindingPriority.Inherited);
Debug.Assert(basePriority > BindingPriority.Animation);
Debug.Assert(priority <= basePriority);
@ -225,7 +234,7 @@ namespace Avalonia.PropertyStore
bv = coerce(owner.Owner, baseValue);
}
if (priority != BindingPriority.Unset && !EqualityComparer<T>.Default.Equals(Value, v))
if (!EqualityComparer<T>.Default.Equals(Value, v))
{
Value = v;
valueChanged = true;
@ -233,9 +242,7 @@ namespace Avalonia.PropertyStore
_uncommon._uncoercedValue = value;
}
if (priority != BindingPriority.Unset &&
(BasePriority == BindingPriority.Unset ||
!EqualityComparer<T>.Default.Equals(_baseValue, bv)))
if (!EqualityComparer<T>.Default.Equals(_baseValue, bv))
{
_baseValue = v;
baseValueChanged = true;

34
src/Avalonia.Base/PropertyStore/ValueStore.cs

@ -7,7 +7,6 @@ using Avalonia.Data;
using Avalonia.Diagnostics;
using Avalonia.Styling;
using Avalonia.Utilities;
using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot;
namespace Avalonia.PropertyStore
{
@ -156,11 +155,12 @@ namespace Avalonia.PropertyStore
return observer;
}
public void ClearLocalValue(AvaloniaProperty property)
public void ClearValue(AvaloniaProperty property)
{
if (TryGetEffectiveValue(property, out var effective) &&
effective.Priority == BindingPriority.LocalValue)
(effective.Priority == BindingPriority.LocalValue || effective.IsOverridenCurrentValue))
{
effective.IsOverridenCurrentValue = false;
ReevaluateEffectiveValue(property, effective, ignoreLocalValue: true);
}
}
@ -209,6 +209,20 @@ namespace Avalonia.PropertyStore
}
}
public void SetCurrentValue<T>(StyledProperty<T> property, T value)
{
if (TryGetEffectiveValue(property, out var v))
{
((EffectiveValue<T>)v).SetCurrentValueAndRaise(this, property, value);
}
else
{
var effectiveValue = new EffectiveValue<T>(Owner, property);
AddEffectiveValue(property, effectiveValue);
effectiveValue.SetCurrentValueAndRaise(this, property, value);
}
}
public object? GetValue(AvaloniaProperty property)
{
if (_effectiveValues.TryGetValue(property, out var v))
@ -235,12 +249,7 @@ namespace Avalonia.PropertyStore
return false;
}
public bool IsSet(AvaloniaProperty property)
{
if (_effectiveValues.TryGetValue(property, out var v))
return v.Priority < BindingPriority.Inherited;
return false;
}
public bool IsSet(AvaloniaProperty property) => _effectiveValues.TryGetValue(property, out _);
public void CoerceValue(AvaloniaProperty property)
{
@ -490,7 +499,7 @@ namespace Avalonia.PropertyStore
if (existing == observer)
{
_localValueBindings?.Remove(property.Id);
ClearLocalValue(property);
ClearValue(property);
}
}
}
@ -616,11 +625,13 @@ namespace Avalonia.PropertyStore
{
object? value;
BindingPriority priority;
bool overridden = false;
if (_effectiveValues.TryGetValue(property, out var v))
{
value = v.Value;
priority = v.Priority;
overridden = v.IsOverridenCurrentValue;
}
else if (property.Inherits && TryGetInheritedValue(property, out v))
{
@ -637,7 +648,8 @@ namespace Avalonia.PropertyStore
property,
value,
priority,
null);
null,
overridden);
}
private int InsertFrame(ValueFrame frame)

44
src/Avalonia.Base/StyledProperty.cs

@ -194,24 +194,48 @@ namespace Avalonia
}
/// <inheritdoc/>
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
internal override IDisposable? RouteSetValue(
AvaloniaObject target,
object? value,
BindingPriority priority)
{
if (ShouldSetValue(target, value, out var converted))
return target.SetValue<TValue>(this, converted, priority);
return null;
}
internal override void RouteSetCurrentValue(AvaloniaObject target, object? value)
{
if (ShouldSetValue(target, value, out var converted))
target.SetCurrentValue<TValue>(this, converted);
}
internal override IDisposable RouteBind(
AvaloniaObject target,
IObservable<object?> source,
BindingPriority priority)
{
return target.Bind<TValue>(this, source, priority);
}
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)]
private bool ShouldSetValue(AvaloniaObject target, object? value, [NotNullWhen(true)] out TValue? converted)
{
if (value == BindingOperations.DoNothing)
{
return null;
converted = default;
return false;
}
else if (value == UnsetValue)
if (value == UnsetValue)
{
target.ClearValue(this);
return null;
converted = default;
return false;
}
else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var converted))
else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var v))
{
return target.SetValue<TValue>(this, (TValue)converted!, priority);
converted = (TValue)v!;
return true;
}
else
{
@ -220,14 +244,6 @@ namespace Avalonia
}
}
internal override IDisposable RouteBind(
AvaloniaObject target,
IObservable<object?> source,
BindingPriority priority)
{
return target.Bind<TValue>(this, source, priority);
}
private object? GetDefaultBoxedValue(Type type)
{
_ = type ?? throw new ArgumentNullException(nameof(type));

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

@ -0,0 +1,308 @@
using System;
using Avalonia.Data;
using Avalonia.Diagnostics;
using Xunit;
using Observable = Avalonia.Reactive.Observable;
namespace Avalonia.Base.UnitTests
{
public class AvaloniaObjectTests_SetCurrentValue
{
[Fact]
public void SetCurrentValue_Sets_Unset_Value()
{
var target = new Class1();
target.SetCurrentValue(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));
}
[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)]
[InlineData(BindingPriority.Animation)]
public void SetCurrentValue_Overrides_Existing_Value(BindingPriority priority)
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "oldvalue", priority);
target.SetCurrentValue(Class1.FooProperty, "newvalue");
Assert.Equal("newvalue", target.GetValue(Class1.FooProperty));
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(priority, GetPriority(target, Class1.FooProperty));
Assert.True(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void SetCurrentValue_Overrides_Inherited_Value()
{
var parent = new Class1();
var target = new Class1 { InheritanceParent = parent };
parent.SetValue(Class1.InheritedProperty, "inheritedvalue");
target.SetCurrentValue(Class1.InheritedProperty, "newvalue");
Assert.Equal("newvalue", target.GetValue(Class1.InheritedProperty));
Assert.True(target.IsSet(Class1.InheritedProperty));
Assert.Equal(BindingPriority.Unset, GetPriority(target, Class1.InheritedProperty));
Assert.True(IsOverridden(target, Class1.InheritedProperty));
}
[Fact]
public void SetCurrentValue_Is_Inherited()
{
var parent = new Class1();
var target = new Class1 { InheritanceParent = parent };
parent.SetCurrentValue(Class1.InheritedProperty, "newvalue");
Assert.Equal("newvalue", target.GetValue(Class1.InheritedProperty));
Assert.False(target.IsSet(Class1.FooProperty));
Assert.Equal(BindingPriority.Inherited, GetPriority(target, Class1.InheritedProperty));
Assert.False(IsOverridden(target, Class1.InheritedProperty));
}
[Fact]
public void ClearValue_Clears_CurrentValue_With_Unset_Priority()
{
var target = new Class1();
target.SetCurrentValue(Class1.FooProperty, "newvalue");
target.ClearValue(Class1.FooProperty);
Assert.Equal("foodefault", target.Foo);
Assert.False(target.IsSet(Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void ClearValue_Clears_CurrentValue_With_Inherited_Priority()
{
var parent = new Class1();
var target = new Class1 { InheritanceParent = parent };
parent.SetValue(Class1.InheritedProperty, "inheritedvalue");
target.SetCurrentValue(Class1.InheritedProperty, "newvalue");
target.ClearValue(Class1.InheritedProperty);
Assert.Equal("inheritedvalue", target.Inherited);
Assert.False(target.IsSet(Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void ClearValue_Clears_CurrentValue_With_LocalValue_Priority()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "localvalue");
target.SetCurrentValue(Class1.FooProperty, "newvalue");
target.ClearValue(Class1.FooProperty);
Assert.Equal("foodefault", target.Foo);
Assert.False(target.IsSet(Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void ClearValue_Clears_CurrentValue_With_Style_Priority()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "stylevalue", BindingPriority.Style);
target.SetCurrentValue(Class1.FooProperty, "newvalue");
target.ClearValue(Class1.FooProperty);
Assert.Equal("stylevalue", target.Foo);
Assert.True(target.IsSet(Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void SetCurrentValue_Can_Be_Coerced()
{
var target = new Class1();
target.SetCurrentValue(Class1.CoercedProperty, 60);
Assert.Equal(60, target.GetValue(Class1.CoercedProperty));
target.CoerceMax = 50;
target.CoerceValue(Class1.CoercedProperty);
Assert.Equal(50, target.GetValue(Class1.CoercedProperty));
target.CoerceMax = 100;
target.CoerceValue(Class1.CoercedProperty);
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)]
[InlineData(BindingPriority.Animation)]
public void SetValue_Overrides_CurrentValue_With_Unset_Priority(BindingPriority priority)
{
var target = new Class1();
target.SetCurrentValue(Class1.FooProperty, "current");
target.SetValue(Class1.FooProperty, "setvalue", priority);
Assert.Equal("setvalue", target.Foo);
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(priority, GetPriority(target, Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void Animation_Value_Overrides_CurrentValue_With_LocalValue_Priority()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "localvalue");
target.SetCurrentValue(Class1.FooProperty, "current");
target.SetValue(Class1.FooProperty, "setvalue", BindingPriority.Animation);
Assert.Equal("setvalue", target.Foo);
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(BindingPriority.Animation, GetPriority(target, Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Fact]
public void StyleTrigger_Value_Overrides_CurrentValue_With_Style_Priority()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "style", BindingPriority.Style);
target.SetCurrentValue(Class1.FooProperty, "current");
target.SetValue(Class1.FooProperty, "setvalue", BindingPriority.StyleTrigger);
Assert.Equal("setvalue", target.Foo);
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(BindingPriority.StyleTrigger, GetPriority(target, Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
}
[Theory]
[InlineData(BindingPriority.LocalValue)]
[InlineData(BindingPriority.Style)]
[InlineData(BindingPriority.Animation)]
public void Binding_Overrides_CurrentValue_With_Unset_Priority(BindingPriority priority)
{
var target = new Class1();
target.SetCurrentValue(Class1.FooProperty, "current");
var s = target.Bind(Class1.FooProperty, Observable.SingleValue("binding"), priority);
Assert.Equal("binding", target.Foo);
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(priority, GetPriority(target, Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
s.Dispose();
Assert.Equal("foodefault", target.Foo);
}
[Fact]
public void Animation_Binding_Overrides_CurrentValue_With_LocalValue_Priority()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "localvalue");
target.SetCurrentValue(Class1.FooProperty, "current");
var s = target.Bind(Class1.FooProperty, Observable.SingleValue("binding"), BindingPriority.Animation);
Assert.Equal("binding", target.Foo);
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(BindingPriority.Animation, GetPriority(target, Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
s.Dispose();
Assert.Equal("current", target.Foo);
}
[Fact]
public void StyleTrigger_Binding_Overrides_CurrentValue_With_Style_Priority()
{
var target = new Class1();
target.SetValue(Class1.FooProperty, "style", BindingPriority.Style);
target.SetCurrentValue(Class1.FooProperty, "current");
var s = target.Bind(Class1.FooProperty, Observable.SingleValue("binding"), BindingPriority.StyleTrigger);
Assert.Equal("binding", target.Foo);
Assert.True(target.IsSet(Class1.FooProperty));
Assert.Equal(BindingPriority.StyleTrigger, GetPriority(target, Class1.FooProperty));
Assert.False(IsOverridden(target, Class1.FooProperty));
s.Dispose();
Assert.Equal("style", target.Foo);
}
private BindingPriority GetPriority(AvaloniaObject target, AvaloniaProperty property)
{
return target.GetDiagnostic(property).Priority;
}
private bool IsOverridden(AvaloniaObject target, AvaloniaProperty property)
{
return target.GetDiagnostic(property).IsOverriddenCurrentValue;
}
private class Class1 : AvaloniaObject
{
public static readonly StyledProperty<string> FooProperty =
AvaloniaProperty.Register<Class1, string>(nameof(Foo), "foodefault");
public static readonly StyledProperty<string> InheritedProperty =
AvaloniaProperty.Register<Class1, string>(nameof(Inherited), "inheriteddefault", inherits: true);
public static readonly StyledProperty<double> CoercedProperty =
AvaloniaProperty.Register<Class1, double>(nameof(Coerced), coerce: Coerce);
public string Foo => GetValue(FooProperty);
public string Inherited => GetValue(InheritedProperty);
public double Coerced => GetValue(CoercedProperty);
public double CoerceMax { get; set; } = 100;
private static double Coerce(AvaloniaObject sender, double value)
{
return Math.Min(value, ((Class1)sender).CoerceMax);
}
}
}
}

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