diff --git a/src/Avalonia.Styling/Controls/INameScope.cs b/src/Avalonia.Styling/Controls/INameScope.cs index 9e21055126..8386157f3d 100644 --- a/src/Avalonia.Styling/Controls/INameScope.cs +++ b/src/Avalonia.Styling/Controls/INameScope.cs @@ -20,6 +20,7 @@ namespace Avalonia.Controls /// /// Finds a named element in the name scope, waits for the scope to be completely populated before returning null + /// Returned task is configured to run any continuations synchronously. /// /// The name. /// The element, or null if the name was not found. diff --git a/src/Avalonia.Styling/Controls/NameScopeLocator.cs b/src/Avalonia.Styling/Controls/NameScopeLocator.cs index 61e5b06402..ac588c2f5a 100644 --- a/src/Avalonia.Styling/Controls/NameScopeLocator.cs +++ b/src/Avalonia.Styling/Controls/NameScopeLocator.cs @@ -49,6 +49,9 @@ namespace Avalonia.Controls } if (_task != null) + // We expect everything to handle callbacks synchronously, + // so the object graph is ready after its built + // so keep TaskContinuationOptions.ExecuteSynchronously _task.ContinueWith(t => { observer.OnNext(t.Result); diff --git a/tests/Avalonia.Controls.UnitTests/NameScopeTests.cs b/tests/Avalonia.Controls.UnitTests/NameScopeTests.cs index 4814057db5..0fdcd3fd34 100644 --- a/tests/Avalonia.Controls.UnitTests/NameScopeTests.cs +++ b/tests/Avalonia.Controls.UnitTests/NameScopeTests.cs @@ -51,6 +51,13 @@ namespace Avalonia.Controls.UnitTests Assert.Throws(() => target.Register("bar", element)); } + + /* + `async void` here is intentional since we expect the continuation to be + executed *synchronously* and behave more like an event handler to make sure that + that the object graph is completely ready to use after it's built + rather than have pending continuations queued by SynchronizationContext. + */ object _found = null; async void FindAsync(INameScope scope, string name) {