Skip to content

Commit

Permalink
fix(Bindings): Avoid propagating DataContext if you are not the child…
Browse files Browse the repository at this point in the history
…'s parent
  • Loading branch information
kazo0 committed Feb 1, 2021
1 parent 8c90b05 commit f95d051
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Private.Infrastructure;
using Uno.Extensions;
using Uno.UI.Extensions;
using Uno.UI.RuntimeTests.Extensions;
using Uno.UI.RuntimeTests.Helpers;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;

namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls
Expand Down Expand Up @@ -231,6 +233,33 @@ public async Task When_Attached_To_TextBlock_Check_Placement()
}
}

[TestMethod]
[RunsOnUIThread]
public async Task Test_Flyout_Binding()
{
#if IS_UNO
var (flyout, content) = CreateFlyoutWithBinding();

var buttonA = new Button()
{
Content = "Button A",
Flyout = flyout,
DataContext = "My Data Context",
};

TestServices.WindowHelper.WindowContent = buttonA;

await TestServices.WindowHelper.WaitForLoaded(buttonA);

buttonA.RaiseClick();

await TestServices.WindowHelper.WaitForLoaded(content);

var stackPanel = content as StackPanel;
Assert.AreEqual("My Data Context", (stackPanel.Children[0] as TextBlock).Text);
#endif
}

private static void VerifyRelativeContentPosition(HorizontalPosition horizontalPosition, VerticalPosition verticalPosition, FrameworkElement content, double minimumTargetOffset, Border target)
{
var contentScreenBounds = content.GetOnScreenBounds();
Expand Down Expand Up @@ -290,6 +319,30 @@ private static void VerifyRelativeContentPosition(HorizontalPosition horizontalP
return (flyout, content);
}

private (Flyout Flyout, FrameworkElement Content) CreateFlyoutWithBinding()
{

var flyout = new Flyout
{
FlyoutPresenterStyle = GetSimpleFlyoutPresenterStyle()
};

var content = new StackPanel
{
Children =
{
new TextBlock().Apply(x => x.SetBinding(TextBlock.TextProperty, new Binding())),
new Button
{
Content = "Button B",
}.Apply(x => x.SetBinding(Button.CommandParameterProperty, new Binding() { Source = flyout }))
}
};

flyout.Content = content;
return (flyout, content);
}

private static Style GetSimpleFlyoutPresenterStyle() => new Style
{
TargetType = typeof(FlyoutPresenter),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public void When_DataContext_Inherited_And_Child_Removed()
Assert.AreEqual(null, SUT.DataContext);
Assert.AreEqual(0, parentCtxChanged);
Assert.AreEqual(1, SUTCtxChanged);
Assert.AreEqual(1, childCtxChanged);
Assert.AreEqual(0, childCtxChanged);
}

[TestMethod]
Expand Down
13 changes: 12 additions & 1 deletion src/Uno.UI/UI/Xaml/DependencyObjectStore.Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,21 @@ void SetInherited(IDependencyObjectStoreProvider provider)
provider.Store.SetInheritedDataContext(inheritedValue);
}
}

for (int i = 0; i < _childrenBindable.Count; i++)
{
var child = _childrenBindable[i];
var parent = child?.GetParent();

//Do not propagate value if you are not this child's parent
//Covers case where a child may hold a binding to a view higher up the tree
//Example: Button A contains a Flyout with Button B inside of it
// Button B has a binding to the Flyout itself
// We should not propagate Button B's DataContext to the Flyout
// since its real parent is actually Button A
if (parent != null && parent != ActualInstance)
{
continue;
}

if (child is IDependencyObjectStoreProvider provider)
{
Expand Down

0 comments on commit f95d051

Please sign in to comment.