Skip to content

Commit

Permalink
fix: Always raise binding value changed when PropertyChanged event is…
Browse files Browse the repository at this point in the history
… raised
  • Loading branch information
Youssef1313 committed Apr 16, 2024
1 parent fe26b2f commit efdd19c
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Page
x:Class="Uno.UI.RuntimeTests.Tests.BindingShouldBeAppliedOnPropertyChangedEvent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.RuntimeTests.Tests"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Page.Resources>
<local:BindingShouldBeAppliedOnPropertyChangedEventConverter x:Key="MyConverter" />
</Page.Resources>

<StackPanel>
<TextBlock x:Name="myTb" Text="{Binding Holder, Converter={StaticResource MyConverter}}" x:FieldModifier="public" />
</StackPanel>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#nullable enable

using System;
using System.ComponentModel;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;

namespace Uno.UI.RuntimeTests.Tests;

public class BindingShouldBeAppliedOnPropertyChangedEventConverter : IValueConverter
{
public int ConvertCount { get; private set; }

public object? Convert(object? value, Type targetType, object parameter, string language)
{
ConvertCount++;
return value is BindingShouldBeAppliedOnPropertyChangedEventValueHolder holder ? holder.Value : null;
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
=> throw new NotSupportedException();
}

public sealed partial class BindingShouldBeAppliedOnPropertyChangedEvent : Page
{
public BindingShouldBeAppliedOnPropertyChangedEvent()
{
this.InitializeComponent();
this.DataContext = new BindingShouldBeAppliedOnPropertyChangedEventVM();
}
}

public class BindingShouldBeAppliedOnPropertyChangedEventVM : INotifyPropertyChanged
{
public BindingShouldBeAppliedOnPropertyChangedEventValueHolder Holder { get; set; } = new();

public event PropertyChangedEventHandler? PropertyChanged;

public void Increment()
{
Holder.Value++;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Holder)));
}
}

public class BindingShouldBeAppliedOnPropertyChangedEventValueHolder
{
public int Value { get; set; }
}
20 changes: 19 additions & 1 deletion src/Uno.UI.RuntimeTests/Tests/BindingTests/BindingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
namespace Uno.UI.RuntimeTests.Tests;

[TestClass]
[RunsOnUIThread]
public class BindingTests
{
[TestMethod]
[RunsOnUIThread]
public async Task When_Binding_Setter_Value_In_Style()
{
var SUT = new BindingToSetterValuePage();
Expand All @@ -31,4 +31,22 @@ void assertBorder(Border border, string expectedSetterValue)
Assert.AreEqual(expectedSetterValue, setter.Value);
}
}

[TestMethod]
public async Task When_BindingShouldBeAppliedOnPropertyChangedEvent()
{
var SUT = new BindingShouldBeAppliedOnPropertyChangedEvent();
await UITestHelper.Load(SUT);

var dc = (BindingShouldBeAppliedOnPropertyChangedEventVM)SUT.DataContext;
var converter = (BindingShouldBeAppliedOnPropertyChangedEventConverter)SUT.Resources["MyConverter"];

Assert.AreEqual(1, converter.ConvertCount);
Assert.AreEqual("0", SUT.myTb.Text);

dc.Increment();

Assert.AreEqual(2, converter.ConvertCount);
Assert.AreEqual("1", SUT.myTb.Text);
}
}
16 changes: 4 additions & 12 deletions src/Uno.UI/DataBinding/BindingPath.BindingItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private void OnDataContextChanged()
}
}

private void OnPropertyChanged(object? previousValue, object? newValue, bool shouldRaiseValueChanged)
private void OnPropertyChanged(object? newValue, bool shouldRaiseValueChanged)
{
if (_isDataContextChanging && newValue == DependencyProperty.UnsetValue)
{
Expand All @@ -211,7 +211,7 @@ private void OnPropertyChanged(object? previousValue, object? newValue, bool sho
Next.DataContext = newValue;
}

if (shouldRaiseValueChanged && previousValue != newValue)
if (shouldRaiseValueChanged)
{
RaiseValueChanged(newValue);
}
Expand Down Expand Up @@ -409,8 +409,6 @@ private IDisposable SubscribeToPropertyChanged()

if (handlerDisposable != null)
{
valueHandler.PreviousValue = GetSourceValue();

// We need to keep the reference to the updatePropertyHandler
// in this disposable. The reference is attached to the source's
// object lifetime, to the target (bound) object.
Expand All @@ -419,11 +417,9 @@ private IDisposable SubscribeToPropertyChanged()
// weak with regards to the delegates that are provided.
disposables.Add(() =>
{
var previousValue = valueHandler.PreviousValue;

valueHandler = null;
handlerDisposable.Dispose();
OnPropertyChanged(previousValue, DependencyProperty.UnsetValue, shouldRaiseValueChanged: false);
OnPropertyChanged(DependencyProperty.UnsetValue, shouldRaiseValueChanged: false);
});
}
}
Expand Down Expand Up @@ -509,18 +505,14 @@ public PropertyChangedValueHandler(BindingItem owner)
_self = WeakReferencePool.RentSelfWeakReference(this);
}

public object? PreviousValue { get; set; }

public ManagedWeakReference WeakReference
=> _self;

public void NewValue()
{
var newValue = _owner.GetSourceValue();

_owner.OnPropertyChanged(PreviousValue, newValue, shouldRaiseValueChanged: true);

PreviousValue = newValue;
_owner.OnPropertyChanged(newValue, shouldRaiseValueChanged: true);
}

public void NewValue(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
Expand Down

0 comments on commit efdd19c

Please sign in to comment.