From 2bff56023bfd4204bb92c355ee867a1eff984cea Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 30 Mar 2020 18:02:30 +0200 Subject: [PATCH 01/21] Added failing test for #3708. --- .../StyledElementTests.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/tests/Avalonia.Styling.UnitTests/StyledElementTests.cs b/tests/Avalonia.Styling.UnitTests/StyledElementTests.cs index 711fcd0708..d66d40e5f7 100644 --- a/tests/Avalonia.Styling.UnitTests/StyledElementTests.cs +++ b/tests/Avalonia.Styling.UnitTests/StyledElementTests.cs @@ -11,6 +11,10 @@ using Xunit; using Avalonia.LogicalTree; using Avalonia.Controls; using System.ComponentModel; +using Avalonia.Controls.Primitives; +using Avalonia.Markup.Xaml.Templates; +using Avalonia.Controls.Templates; +using Avalonia.Data; namespace Avalonia.Styling.UnitTests { @@ -575,6 +579,53 @@ namespace Avalonia.Styling.UnitTests Times.Once); } + [Fact] + public void SetParent_Does_Not_Crash_Due_To_Reentrancy() + { + // Issue #3708 + var app = UnitTestApplication.Start(TestServices.StyledWindow); + + ContentControl target; + var root = new TestRoot + { + DataContext = false, + Child = target = new ContentControl + { + Styles = + { + new Style(x => x.OfType()) + { + Setters = + { + new Setter( + ContentControl.ContentProperty, + new FuncTemplate(() => new TextBlock { Text = "Enabled" })), + }, + }, + new Style(x => x.OfType().Class(":disabled")) + { + Setters = + { + new Setter( + ContentControl.ContentProperty, + new FuncTemplate(() => new TextBlock { Text = "Disabled" })), + }, + }, + }, + [!ContentControl.IsEnabledProperty] = new Binding(), + } + }; + + root.Measure(Size.Infinity); + root.Arrange(new Rect(0, 0, 100, 100)); + + var textBlock = Assert.IsType(target.Content); + Assert.Equal("Disabled", textBlock.Text); + + // #3708 was crashing here with AvaloniaInternalException. + root.Child = null; + } + private interface IDataContextEvents { event EventHandler DataContextBeginUpdate; From 18d2238b91b00302f676297788ff5848c5c8252a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 30 Mar 2020 20:21:54 +0200 Subject: [PATCH 02/21] Remove sanity check from SetParent. In the case of #3708, the sanity check fails because the parent call to `SetParent` hasn't yet completed - it's the setting of `InheritanceParent` on the parent that causes the child to get attached. --- src/Avalonia.Styling/StyledElement.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index 241ca1d0ec..1a4bc5b3a3 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -453,18 +453,14 @@ namespace Avalonia NotifyResourcesChanged(new ResourcesChangedEventArgs()); - if (Parent is ILogicalRoot || Parent?.IsAttachedToLogicalTree == true || this is ILogicalRoot) - { - var newRoot = FindLogicalRoot(this); - - if (newRoot == null) - { - throw new AvaloniaInternalException("Parent is attached to logical tree but cannot find root."); - } + var newRoot = FindLogicalRoot(this); + if (newRoot is object) + { var e = new LogicalTreeAttachmentEventArgs(newRoot, this, parent); OnAttachedToLogicalTreeCore(e); } + #nullable disable RaisePropertyChanged( ParentProperty, @@ -618,7 +614,7 @@ namespace Avalonia } } - private static ILogicalRoot? FindLogicalRoot(IStyleHost e) + private static ILogicalRoot? FindLogicalRoot(IStyleHost? e) { while (e != null) { From bce28b3d35bb71bc4a9f5f2f5a1a292734aa6e4a Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 31 Mar 2020 17:57:41 +0300 Subject: [PATCH 03/21] Fixed InitialFileName for GTK-based file dialog --- samples/ControlCatalog/Pages/DialogsPage.xaml.cs | 5 +++-- src/Avalonia.X11/NativeDialogs/Gtk.cs | 3 +++ src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index d207689223..6f5e503fb3 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -42,14 +42,15 @@ namespace ControlCatalog.Pages new SaveFileDialog() { Title = "Save file", - Filters = GetFilters() + Filters = GetFilters(), + InitialFileName = "test.txt" }.ShowAsync(GetWindow()); }; this.FindControl