diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index a7aafbf6e8..d4777b2f8a 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -774,7 +774,9 @@ namespace Avalonia.Controls foreach (var child in control.LogicalChildren) { - if (child is Control c && !c.IsSet(DataContextProperty)) + if (child is Control c && + c.InheritanceParent == control && + !c.IsSet(DataContextProperty)) { DataContextNotifying(c, notifying); } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs index ccbf04533d..85a450e1dc 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs @@ -249,6 +249,37 @@ namespace Avalonia.Controls.UnitTests.Primitives } } + [Fact] + public void DataContextBeginUpdate_Should_Not_Be_Called_For_Controls_That_Dont_Inherit() + { + using (CreateServices()) + { + TestControl child; + var popup = new Popup + { + Child = child = new TestControl(), + DataContext = "foo", + }; + + var beginCalled = false; + child.DataContextBeginUpdate += (s, e) => beginCalled = true; + + // Test for #1245. Here, the child's logical parent is the popup but it's not yet + // attached to a visual tree because the popup hasn't been opened. + Assert.Same(popup, ((ILogical)child).LogicalParent); + Assert.Same(popup, child.InheritanceParent); + Assert.Null(child.GetVisualRoot()); + + popup.Open(); + + // #1245 was caused by the fact that DataContextBeginUpdate was called on `target` + // when the PopupRoot was created, even though PopupRoot isn't the + // InheritanceParent of child. + Assert.False(beginCalled); + } + } + + private static IDisposable CreateServices() { var result = AvaloniaLocator.EnterScope(); @@ -304,5 +335,18 @@ namespace Avalonia.Controls.UnitTests.Primitives private class PopupContentControl : ContentControl { } + + private class TestControl : Decorator + { + public event EventHandler DataContextBeginUpdate; + + public new IAvaloniaObject InheritanceParent => base.InheritanceParent; + + protected override void OnDataContextBeginUpdate() + { + DataContextBeginUpdate?.Invoke(this, EventArgs.Empty); + base.OnDataContextBeginUpdate(); + } + } } }