unoplatform / uno

Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported.
https://platform.uno
Apache License 2.0
8.74k stars 705 forks source link

Loading ContentPresenter stackoverflows (possibly a regression?) #17470

Open Youssef1313 opened 1 month ago

Youssef1313 commented 1 month ago

Current behavior

When the following test executes for ContentPresenter, it stackoverflows :(

​  [TestMethod]
  [RunsOnUIThread]
  [DataRow(typeof(Grid))]
  [DataRow(typeof(StackPanel))]
  [DataRow(typeof(Border))]
  [DataRow(typeof(ContentPresenter))]
  public async Task MyTest(Type type)
  {
    var control = (FrameworkElement)Activator.CreateInstance(type);

    control.Width = 200;
    control.Height = 200;

    await UITestHelper.Load(control);
  }

Expected behavior

No response

How to reproduce it (as minimally and precisely as possible)

No response

Workaround

No response

Works on UWP/WinUI

None

Environment

No response

NuGet package version(s)

No response

Affected platforms

No response

IDE

No response

IDE version

No response

Relevant plugins

No response

Anything else we need to know?

No response

Youssef1313 commented 1 month ago

@ramezgerges Could it be a regression from recent ContentPresenter changes?

ramezgerges commented 1 month ago

I couldn't reproduce this on my machine (on Windows with latest master).

Youssef1313 commented 1 month ago

@MartinZikmund Can you check if you can repro or if it's just me somehow? :/

MartinZikmund commented 2 weeks ago

I have tested this by adding the snippet above in Given_ContentControl.cs (you can even just keep the [DataRow(ContentPresenter)], others are not needed) and indeed it stack overflows for me on Skia.Generic and on UnoIslandsSamplesApp.Skia.Wpf. Based on my debugging the problem is as follows:

  1. ContentPresenter is constructed
  2. OnApplyTemplate is called
  3. Inside the binding to Content is created - binding to ContentControl.Content of the TemplatedParent of the ContentPresenter
  4. Incorrectly the TemplatedParent is assumed to be SampleControl - which applies its content (UnitTestsPage) as the Content of the tested ContentPresenter - thus creating a circular visual tree where the parent of the page is the grand child ContentPresenter
  5. The stack overflow just occurs on "LostFocus" event which is bubbling up from the button that runs the test up and which just ends up in infinite loop -> Page -> ContentPresenter -> up towards Page -> ContentPresenter -> ...
MartinZikmund commented 2 weeks ago

I assume the problem that needs to be fixed here is the fact that TemplatedParent of the ContentPresenter should just be null, as it is actually not part of a template. Adding @ramezgerges and @Xiaoy312

Youssef1313 commented 2 weeks ago

Let's wait for Xiao's work then.

MartinZikmund commented 2 weeks ago

To debug this most easily, adjust the SetParent method in src\Uno.UI\UI\Xaml\DependencyObjectExtensions.cs as follows:

image

You will be able to see that this gets executed for UnitTestsPage once when it is first opened, and then the second time after the unit test starts - setting the page's Parent to be its grand child ContentPresenter