Skip to content

Commit

Permalink
perf: Refactor DependencyPropertyDetails
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Sep 8, 2024
1 parent 7064342 commit 8ce4d21
Show file tree
Hide file tree
Showing 24 changed files with 399 additions and 489 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,6 @@ public void When_Unsubscribe_From_PropertyChanges()
Assert.AreEqual(0, changedCount);
}

#if HAS_UNO
[TestMethod]
public void When_GetValueUnderPrecedence()
{
var grid = new Grid();
grid.Tag = "LocalValue";

var (actualValue1, actualPrecedence1) = grid.GetValueUnderPrecedence(FrameworkElement.TagProperty, DependencyPropertyValuePrecedences.Coercion);
Assert.AreEqual("LocalValue", (string)actualValue1);
Assert.AreEqual(DependencyPropertyValuePrecedences.Local, actualPrecedence1);

var (actualValue2, actualPrecedence2) = grid.GetValueUnderPrecedence(FrameworkElement.TagProperty, DependencyPropertyValuePrecedences.Local);
Assert.IsNull(actualValue2);
Assert.AreEqual(DependencyPropertyValuePrecedences.DefaultValue, actualPrecedence2);
}
#endif

[TestMethod]
public void When_CreateDefaultValueCallback()
{
Expand Down
22 changes: 0 additions & 22 deletions src/Uno.UI.Tests/BinderTests/Given_BindingPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ public void When_WithHigherPrecedence_SetValue_Then_ValueUpdated()
sut.Value = "Animations"; // Animations

Assert.AreEqual("Animations", target.Value);

Assert.AreEqual("Animations", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Animations));
}

[TestMethod]
Expand All @@ -45,9 +43,6 @@ public void When_WithHigherPrecedence_SetValueAndLocalValue_Then_ValueUpdated()

// Local value takes over Animations if it's newer.
Assert.AreEqual("Local", target.Value);

Assert.AreEqual("Local", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Animations));
Assert.AreEqual("Local", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Local));
}

[TestMethod]
Expand All @@ -60,9 +55,6 @@ public void When_WithHigherPrecedence_SetValueAndLocalValueAndClear_Then_ValueUp
sut.ClearValue();

Assert.AreEqual("Local", target.Value);

Assert.AreEqual(DependencyProperty.UnsetValue, target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Animations));
Assert.AreEqual("Local", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Local));
}

[TestMethod]
Expand All @@ -76,9 +68,6 @@ public void When_WithHigherPrecedence_SetValueAndClear_SetTargetValue_Then_Value
target.Value = "TargetLocalValue";

Assert.AreEqual("TargetLocalValue", target.Value);

Assert.AreEqual(DependencyProperty.UnsetValue, target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Animations));
Assert.AreEqual("TargetLocalValue", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Local));
}

[TestMethod]
Expand All @@ -90,8 +79,6 @@ public void When_WithLowerPrecedence_SetValue_Then_ValueUpdated()
sut.Value = "Inherit";

Assert.AreEqual("CustomDefaultLocalValue", target.Value);

Assert.AreEqual("Inherit", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Inheritance));
}

[TestMethod]
Expand All @@ -103,9 +90,6 @@ public void When_WithLowerPrecedence_SetValueAndLocalValue_Then_ValueUpdated()
sut.SetLocalValue("Local");

Assert.AreEqual("Local", target.Value);

Assert.AreEqual("Local", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Local));
Assert.AreEqual("Inherit", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Inheritance));
}

[TestMethod]
Expand All @@ -118,9 +102,6 @@ public void When_WithLowerPrecedence_SetValueAndLocalValueAndClear_Then_ValueUpd
sut.ClearValue();

Assert.AreEqual("Local", target.Value);

Assert.AreEqual(DependencyProperty.UnsetValue, target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Animations));
Assert.AreEqual("Local", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Local));
}

[TestMethod]
Expand All @@ -134,9 +115,6 @@ public void When_WithLowerPrecedence_SetValueAndClear_SetTargetValue_Then_ValueU
target.Value = "TargetLocalValue";

Assert.AreEqual("TargetLocalValue", target.Value);

Assert.AreEqual(DependencyProperty.UnsetValue, target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Animations));
Assert.AreEqual("TargetLocalValue", target.GetPrecedenceSpecificValue(MyTarget.ValueProperty, DependencyPropertyValuePrecedences.Local));
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public void When_DefaultValueProvider_Registered_Provides_Value()
{
var test = new DefaultValueProviderSample();

var value = test.GetPrecedenceSpecificValue(DefaultValueProviderSample.TestProperty, DependencyPropertyValuePrecedences.DefaultValue);
var value = test.Test;
Assert.AreEqual(3, value);
}

Expand All @@ -28,7 +28,7 @@ public void When_DefaultValueProvider_Registered_Other_Property_Not_Affected()
{
var test = new DefaultValueProviderSample();

var value = test.GetPrecedenceSpecificValue(DefaultValueProviderSample.OtherProperty, DependencyPropertyValuePrecedences.DefaultValue);
var value = test.Other;
Assert.AreEqual(0, value);
}

Expand All @@ -37,7 +37,7 @@ public void When_DefaultValueProvider_Multiple_Registered_Overwrite()
{
var test = new InheritedDefaultValueProviderSample();

var value = test.GetPrecedenceSpecificValue(DefaultValueProviderSample.TestProperty, DependencyPropertyValuePrecedences.DefaultValue);
var value = test.Test;
Assert.AreEqual(17, value);
}

Expand All @@ -46,7 +46,7 @@ public void When_DefaultValueProvider_Multiple_Registered_Unaffected()
{
var test = new InheritedDefaultValueProviderSample2();

var value = test.GetPrecedenceSpecificValue(DefaultValueProviderSample.TestProperty, DependencyPropertyValuePrecedences.DefaultValue);
var value = test.Test;
Assert.AreEqual(3, value); // GetDefaultValue should apply
}

Expand All @@ -55,7 +55,6 @@ public void When_GetDefaultValue()
{
var expected = 42;
var defaultValueTest = new DefaultValueTest();
Assert.AreEqual(expected, defaultValueTest.GetPrecedenceSpecificValue(DefaultValueTest.TestValueProperty, DependencyPropertyValuePrecedences.DefaultValue));
Assert.AreEqual(expected, defaultValueTest.GetValue(DefaultValueTest.TestValueProperty));
Assert.AreEqual(expected, (defaultValueTest as IDependencyObjectStoreProvider).Store.GetDefaultValue(DefaultValueTest.TestValueProperty));
Assert.AreEqual(expected, defaultValueTest.TestValue);
Expand Down
24 changes: 0 additions & 24 deletions src/Uno.UI.Tests/DependencyProperty/Given_DependencyProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1717,18 +1717,6 @@ public void When_Set_With_Both_Style_And_LocalValue()
sut.PropA.Should().Be("LocalValue");
sut.PropB.Should().Be("StyleValueForB");

#if !NETFX_CORE // this part of the test not possible on UWP - extensive check for Uno
sut.GetValueForEachPrecedences(MyDependencyObject.PropAProperty).Select(v => v.value)
.Should().HaveElementAt((int)DependencyPropertyValuePrecedences.DefaultValue, null)
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.ExplicitStyle, "StyleValue")
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.Local, "LocalValue");

sut.GetValueForEachPrecedences(MyDependencyObject.PropBProperty).Select(v => v.value)
.Should().HaveElementAt((int)DependencyPropertyValuePrecedences.DefaultValue, null)
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.ExplicitStyle, "StyleValueForB")
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.Local, UnsetValue.Instance);
#endif

sut.ClearValue(MyDependencyObject.PropBProperty);
sut.PropB.Should().Be("StyleValueForB");

Expand All @@ -1746,18 +1734,6 @@ public void When_Set_With_Both_Style_And_LocalValue()

sut.PropA.Should().Be(null);
sut.PropB.Should().Be(null);

#if !NETFX_CORE // this part of the test not possible on UWP - extensive check for Uno
sut.GetValueForEachPrecedences(MyDependencyObject.PropAProperty).Select(v => v.value)
.Should().HaveElementAt((int)DependencyPropertyValuePrecedences.DefaultValue, null)
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.ExplicitStyle, UnsetValue.Instance)
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.Local, UnsetValue.Instance);

sut.GetValueForEachPrecedences(MyDependencyObject.PropBProperty).Select(v => v.value)
.Should().HaveElementAt((int)DependencyPropertyValuePrecedences.DefaultValue, null)
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.ExplicitStyle, UnsetValue.Instance)
.And.HaveElementAt((int)DependencyPropertyValuePrecedences.Local, null); // because of the callback ;-)
#endif
}

[TestMethod]
Expand Down
4 changes: 2 additions & 2 deletions src/Uno.UI/DataBinding/BindingExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,12 +462,12 @@ private void SetTargetValue(object value)
// It may be related to https://github.com/unoplatform/uno/issues/190
try
{
DependencyPropertyDetails.SuppressLocalCanDefeatAnimations();
ModifiedValue.SuppressLocalCanDefeatAnimations();
GetValueSetter()(viewTarget, value);
}
finally
{
DependencyPropertyDetails.ContinueLocalCanDefeatAnimations();
ModifiedValue.ContinueLocalCanDefeatAnimations();
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/DataBinding/BindingPath.BindingItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ private void BuildSubstituteValueGetter()
}

_substituteValueGetter =
BindingPropertyHelper.GetSubstituteValueGetter(_dataContextType, PropertyName, DependencyPropertyValuePrecedences.Animations);
BindingPropertyHelper.GetSubstituteValueGetter(_dataContextType, PropertyName);
}
}

Expand Down
57 changes: 5 additions & 52 deletions src/Uno.UI/DataBinding/BindingPropertyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ internal static partial class BindingPropertyHelper
//
private static Dictionary<GetValueGetterCacheKey, ValueGetterHandler> _getValueGetter = new(GetValueGetterCacheKey.Comparer);
private static Dictionary<GetValueSetterCacheKey, ValueSetterHandler> _getValueSetter = new(GetValueSetterCacheKey.Comparer);
private static Dictionary<GenericPropertyCacheKey, ValueGetterHandler> _getPrecedenceSpecificValueGetter = new(GenericPropertyCacheKey.Comparer);
private static Dictionary<GenericPropertyCacheKey, ValueGetterHandler> _getSubstituteValueGetter = new(GenericPropertyCacheKey.Comparer);
private static Dictionary<GenericPropertyCacheKey, ValueUnsetterHandler> _getValueUnsetter = new(GenericPropertyCacheKey.Comparer);
private static Dictionary<EventCacheKey, bool> _isEvent = new(EventCacheKey.Comparer);
Expand All @@ -71,7 +70,6 @@ internal static void ClearCaches()
{
_getValueGetter.Clear();
_getValueSetter.Clear();
_getPrecedenceSpecificValueGetter.Clear();
_getSubstituteValueGetter.Clear();
_getValueUnsetter.Clear();
_isEvent.Clear();
Expand Down Expand Up @@ -174,34 +172,17 @@ internal static ValueSetterHandler GetValueSetter(Type type, string property, bo
return result;
}

internal static ValueGetterHandler GetPrecedenceSpecificValueGetter(Type type, string property, DependencyPropertyValuePrecedences precedence)
internal static ValueGetterHandler GetSubstituteValueGetter(Type type, string property)
{
var key = new GenericPropertyCacheKey(type, property, precedence);

ValueGetterHandler? result;

lock (_getPrecedenceSpecificValueGetter)
{
if (!_getPrecedenceSpecificValueGetter.TryGetValue(key, out result))
{
_getPrecedenceSpecificValueGetter.Add(key, result = InternalGetPrecedenceSpecificValueGetter(type, property, precedence));
}
}

return result;
}

internal static ValueGetterHandler GetSubstituteValueGetter(Type type, string property, DependencyPropertyValuePrecedences precedence)
{
var key = new GenericPropertyCacheKey(type, property, precedence);
var key = new GenericPropertyCacheKey(type, property, DependencyPropertyValuePrecedences.Animations);

ValueGetterHandler? result;

lock (_getSubstituteValueGetter)
{
if (!_getSubstituteValueGetter.TryGetValue(key, out result))
{
_getSubstituteValueGetter.Add(key, result = InternalGetSubstituteValueGetter(type, property, precedence));
_getSubstituteValueGetter.Add(key, result = InternalGetSubstituteValueGetter(type, property));
}
}

Expand Down Expand Up @@ -1109,35 +1090,7 @@ private static ValueSetterHandler InternalGetValueSetter(Type type, string prope
}
}

private static ValueGetterHandler InternalGetPrecedenceSpecificValueGetter(Type type, string property, DependencyPropertyValuePrecedences precedence)
{
if (type == typeof(UnsetValue))
{
return UnsetValueGetter;
}

property = SanitizePropertyName(type, property);

var dp = FindDependencyProperty(type, property);

if (dp != null)
{
return (instance) => DependencyObjectExtensions.GetPrecedenceSpecificValue((DependencyObject)instance, dp, precedence);
}

{
// No getter has been found
var empty = Funcs.CreateMemoized<object>(() =>
{
_log.ErrorFormat("The [{0}] precedence specific property getter does not exist on type [{1}]", property, type);
return DependencyProperty.UnsetValue;
});

return instance => empty();
}
}

private static ValueGetterHandler InternalGetSubstituteValueGetter(Type type, string property, DependencyPropertyValuePrecedences precedence)
private static ValueGetterHandler InternalGetSubstituteValueGetter(Type type, string property)
{
if (type == typeof(UnsetValue))
{
Expand All @@ -1150,7 +1103,7 @@ private static ValueGetterHandler InternalGetSubstituteValueGetter(Type type, st

if (dp != null)
{
return (instance) => DependencyObjectExtensions.GetValueUnderPrecedence((DependencyObject)instance, dp, precedence).value;
return (instance) => DependencyObjectExtensions.GetBaseValue(instance, dp);
}

{
Expand Down
4 changes: 2 additions & 2 deletions src/Uno.UI/UI/Xaml/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ private void OnResourcesChanged(ResourceUpdateReason updateReason)
// with the newly evaluated ThemeResource value.
// In this case, if we previously had Animation value in effect, we don't want the new Local value to take effect.
// So, we avoid setting LocalValueNewerThanAnimationsValue
DependencyPropertyDetails.SuppressLocalCanDefeatAnimations();
ModifiedValue.SuppressLocalCanDefeatAnimations();
DefaultBrushes.ResetDefaultThemeBrushes();
foreach (var contentRoot in WinUICoreServices.Instance.ContentRootCoordinator.ContentRoots)
{
Expand Down Expand Up @@ -485,7 +485,7 @@ View GetTreeRoot(ContentRoot contentRoot)
}
finally
{
DependencyPropertyDetails.ContinueLocalCanDefeatAnimations();
ModifiedValue.ContinueLocalCanDefeatAnimations();
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/Uno.UI/UI/Xaml/Controls/Control/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private protected virtual object CoerceIsEnabled(object baseValue, DependencyPro

var parentValue = precedence == DependencyPropertyValuePrecedences.Inheritance ?
baseValue :
this.GetValue(IsEnabledProperty, DependencyPropertyValuePrecedences.Inheritance);
((IDependencyObjectStoreProvider)this).Store.ReadInheritedValueOrDefaultValue(IsEnabledProperty);

// If the parent is disabled, this control must be disabled as well
if (parentValue is false)
Expand All @@ -172,7 +172,8 @@ private protected virtual object CoerceIsEnabled(object baseValue, DependencyPro
}

// otherwise use the more local value
var (localValue, localPrecedence) = this.GetValueUnderPrecedence(IsEnabledProperty, DependencyPropertyValuePrecedences.Coercion);
var store = ((IDependencyObjectStoreProvider)this).Store;
var (localValue, localPrecedence) = store.GetBaseValue(IsEnabledProperty);

if (localPrecedence >= precedence) // > means weaker precedence
{
Expand Down
11 changes: 11 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/Control/Control.mux.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,5 +225,16 @@ private static void ProcessAcceleratorsIfApplicable(KeyRoutedEventArgs spArgsAsK
}

private protected static VirtualKeyModifiers GetKeyboardModifiers() => CoreImports.Input_GetKeyboardModifiers();

internal bool TryGetValueFromBuiltInStyle(DependencyProperty dp, out object? value)
{
if (Style.GetDefaultStyleForType(GetDefaultStyleKey()) is { } style)
{
return style.TryGetPropertyValue(dp, out value, this);
}

value = null;
return false;
}
}
}
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/Controls/Popup/Popup.Base.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ partial void OnIsOpenChangedPartial(bool oldIsOpen, bool newIsOpen)
partial void OnChildChangedPartial(UIElement oldChild, UIElement newChild)
{
if (oldChild is IDependencyObjectStoreProvider provider &&
provider.Store.GetValue(provider.Store.DataContextProperty, DependencyPropertyValuePrecedences.Local, true) != DependencyProperty.UnsetValue)
provider.Store.ReadLocalValue(provider.Store.DataContextProperty) != DependencyProperty.UnsetValue)
{
provider.Store.ClearValue(provider.Store.TemplatedParentProperty, DependencyPropertyValuePrecedences.Local);
provider.Store.ClearValue(AllowFocusOnInteractionProperty, DependencyPropertyValuePrecedences.Local);
Expand Down
Loading

0 comments on commit 8ce4d21

Please sign in to comment.