Skip to content

Commit

Permalink
fix(dependencyobject): Clear binding on ClearValue
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed Dec 22, 2022
1 parent bb45d4d commit 9b2f394
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/Uno.UI.Tests/BinderTests/Given_Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,55 @@ public void When_Binding_OneWay_Overwritten_By_Local_Explicit_Source()
Assert.AreEqual(22, slider.Value);
}

[TestMethod]
public void When_Binding_And_ClearValue()
{
var SUT = new MyControl();

SUT.SetBinding(MyControl.MyPropertyProperty, new Binding { Path = new PropertyPath(".") });

SUT.DataContext = 42;

Assert.AreEqual(42, SUT.MyProperty);

SUT.ClearValue(MyControl.MyPropertyProperty);

SUT.DataContext = 43;

Assert.AreEqual(0, SUT.MyProperty);
}

[TestMethod]
public void When_Binding_And_ClearValue_With_Events()
{
List<int> myPropertyHistory = new();
var SUT = new MyControl();

SUT.SetBinding(MyControl.MyPropertyProperty, new Binding { Path = new PropertyPath(".") });

SUT.RegisterPropertyChangedCallback(
MyControl.MyPropertyProperty,
(s, e) => {
myPropertyHistory.Add(SUT.MyProperty);
});

SUT.DataContext = 42;

Assert.AreEqual(42, SUT.MyProperty);
Assert.AreEqual(1, myPropertyHistory.Count);
Assert.AreEqual(42, myPropertyHistory[0]);

SUT.ClearValue(MyControl.MyPropertyProperty);

Assert.AreEqual(2, myPropertyHistory.Count);
Assert.AreEqual(0, myPropertyHistory[1]);

SUT.DataContext = 43;

Assert.AreEqual(2, myPropertyHistory.Count);
Assert.AreEqual(0, SUT.MyProperty);
}

public partial class BaseTarget : DependencyObject
{
private List<object> _dataContextChangedList = new List<object>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<UserControl x:Class="Uno.UI.Tests.Windows_UI_Xaml.Controls.When_StaticResource_And_VisualState_Setter_ClearValue"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.Tests.Windows_UI_Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="OuterElementTopLevel"
x:FieldModifier="public"
mc:Ignorable="d">
<Grid>
<Grid.Resources>
<x:String x:Key="resource1">my static resource</x:String>
</Grid.Resources>


<ContentControl x:Name="topLevel"
x:FieldModifier="public"
Tag="Default Value">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="DefaultState" />
<VisualState x:Name="NewState">
<VisualState.Setters>
<Setter Target="innerContent.Tag" Value="42" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<ContentPresenter x:Name="innerContent"
Content="{TemplateBinding Content}"
Tag="{StaticResource resource1}" />
</Grid>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
</Grid>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236

namespace Uno.UI.Tests.Windows_UI_Xaml.Controls
{
public sealed partial class When_StaticResource_And_VisualState_Setter_ClearValue : UserControl
{
public When_StaticResource_And_VisualState_Setter_ClearValue()
{
this.InitializeComponent();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<UserControl x:Class="Uno.UI.Tests.Windows_UI_Xaml.Controls.When_TemplateBinding_And_VisualState_Setter_ClearValue"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.Tests.Windows_UI_Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="OuterElementTopLevel"
x:FieldModifier="public"
mc:Ignorable="d">
<Grid>
<ContentControl x:Name="topLevel"
x:FieldModifier="public"
Tag="Default Value">
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="DefaultState" />
<VisualState x:Name="NewState">
<VisualState.Setters>
<Setter Target="innerContent.Tag" Value="42" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

<ContentPresenter x:Name="innerContent" Content="{TemplateBinding Content}" Tag="{TemplateBinding Tag}" />
</Grid>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
</Grid>
</UserControl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236

namespace Uno.UI.Tests.Windows_UI_Xaml.Controls
{
public sealed partial class When_TemplateBinding_And_VisualState_Setter_ClearValue : UserControl
{
public When_TemplateBinding_And_VisualState_Setter_ClearValue()
{
this.InitializeComponent();
}
}
}
45 changes: 45 additions & 0 deletions src/Uno.UI.Tests/Windows_UI_Xaml/Given_ThemeResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,51 @@ public void ThemeResource_When_Setter_Override_State_From_Visual_Parent()
Assert.AreEqual(Colors.Orange, (tb.Foreground as SolidColorBrush)?.Color);
}

[TestMethod]
public void When_TemplateBinding_And_VisualState_Setter_ClearValue()
{
var SUT = new When_TemplateBinding_And_VisualState_Setter_ClearValue();
SUT.topLevel.Content = "test";
SUT.topLevel.ApplyTemplate();

var inner = SUT.FindName("innerContent") as ContentPresenter;
Assert.IsNotNull(inner);
Assert.AreEqual("Default Value", inner.Tag);

VisualStateManager.GoToState(SUT.topLevel, "NewState", true);
Assert.AreEqual("42", inner.Tag);

VisualStateManager.GoToState(SUT.topLevel, "DefaultState", true);
Assert.AreEqual("Default Value", inner.Tag);

SUT.topLevel.Tag = "Updated value";
Assert.AreEqual("Updated value", inner.Tag);
}

[TestMethod]
public void When_StaticResource_And_VisualState_Setter_ClearValue()
{
var SUT = new When_StaticResource_And_VisualState_Setter_ClearValue();
SUT.topLevel.Content = "test";
SUT.topLevel.ApplyTemplate();

var inner = SUT.FindName("innerContent") as ContentPresenter;
Assert.IsNotNull(inner);
Assert.AreEqual("my static resource", inner.Tag);

VisualStateManager.GoToState(SUT.topLevel, "NewState", true);
Assert.AreEqual("42", inner.Tag);

VisualStateManager.GoToState(SUT.topLevel, "DefaultState", true);
Assert.AreEqual("my static resource", inner.Tag);

VisualStateManager.GoToState(SUT.topLevel, "NewState", true);
Assert.AreEqual("42", inner.Tag);

VisualStateManager.GoToState(SUT.topLevel, "DefaultState", true);
Assert.AreEqual("my static resource", inner.Tag);
}

/// <summary>
/// Use Fluent styles for the duration of the test.
/// </summary>
Expand Down
18 changes: 18 additions & 0 deletions src/Uno.UI/UI/Xaml/DependencyObjectStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Uno.UI;
using System.Collections;
using System.Globalization;
using Windows.ApplicationModel.Calls;

#if XAMARIN_ANDROID
using View = Android.Views.View;
Expand Down Expand Up @@ -464,6 +465,8 @@ private void InnerSetValue(DependencyProperty property, object? value, Dependenc
// Resolve the stack once for the instance, for performance.
propertyDetails ??= _properties.GetPropertyDetails(property);

TryClearBinding(value, propertyDetails);

var previousValue = GetValue(propertyDetails);
var previousPrecedence = GetCurrentHighestValuePrecedence(propertyDetails);

Expand Down Expand Up @@ -515,6 +518,21 @@ private void InnerSetValue(DependencyProperty property, object? value, Dependenc
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void TryClearBinding(object? value, DependencyPropertyDetails propertyDetails)
{
if (object.ReferenceEquals(value, DependencyProperty.UnsetValue))
{
var hasTemplatedParentBinding =
propertyDetails.GetBinding()?.ParentBinding.RelativeSource?.Mode == RelativeSourceMode.TemplatedParent;

if (!hasTemplatedParentBinding)
{
propertyDetails.ClearBinding();
}
}
}

private void TryUpdateInheritedAttachedProperty(DependencyProperty property, DependencyPropertyDetails propertyDetails)
{
if (
Expand Down

0 comments on commit 9b2f394

Please sign in to comment.