diff --git a/src/Uno.Extensions.Core/IDispatcher.cs b/src/Uno.Extensions.Core/IDispatcher.cs
index c174969c03..02f18592f2 100644
--- a/src/Uno.Extensions.Core/IDispatcher.cs
+++ b/src/Uno.Extensions.Core/IDispatcher.cs
@@ -10,4 +10,9 @@ public interface IDispatcher
/// An cancellation token to cancel the async operation.
/// A ValueTask to asynchronously get the result of the operation.
ValueTask ExecuteAsync(AsyncFunc func, CancellationToken cancellation);
+
+ ///
+ /// Gets a value that specifies whether the current execution context is on the UI thread.
+ ///
+ bool HasThreadAccess { get; }
}
diff --git a/src/Uno.Extensions.Core/PlatformHelper.cs b/src/Uno.Extensions.Core/PlatformHelper.cs
index b5728c2f62..602d810909 100644
--- a/src/Uno.Extensions.Core/PlatformHelper.cs
+++ b/src/Uno.Extensions.Core/PlatformHelper.cs
@@ -1,6 +1,6 @@
namespace Uno.Extensions;
-public class PlatformHelper
+public static class PlatformHelper
{
private static bool _isNetCore;
private static bool _initialized;
@@ -30,6 +30,15 @@ public static bool IsNetCore
}
}
+ ///
+ /// Determines if the current runtime supports threading
+ ///
+ public static bool IsThreadingEnabled
+ { get; } = !IsWebAssembly || IsWebAssemblyThreadingSupported;
+
+ private static bool IsWebAssemblyThreadingSupported { get; } = Environment.GetEnvironmentVariable("UNO_BOOTSTRAP_MONO_RUNTIME_CONFIGURATION").StartsWith("threads", StringComparison.OrdinalIgnoreCase);
+
+
///
/// Initialization is performed explicitly to avoid a mono/mono issue regarding .cctor and FullAOT
/// see https://github.com/unoplatform/uno/issues/5395
diff --git a/src/Uno.Extensions.Navigation.UI/Dispatcher.cs b/src/Uno.Extensions.Navigation.UI/Dispatcher.cs
index ac29d551d1..b8f592eedb 100644
--- a/src/Uno.Extensions.Navigation.UI/Dispatcher.cs
+++ b/src/Uno.Extensions.Navigation.UI/Dispatcher.cs
@@ -33,5 +33,15 @@ public Dispatcher(FrameworkElement element)
///
public async ValueTask ExecuteAsync(AsyncFunc func, CancellationToken cancellation)
- => await _dispatcher.ExecuteAsync(func, cancellation);
+ {
+ if (PlatformHelper.IsThreadingEnabled &&
+ HasThreadAccess)
+ {
+ return await func(cancellation);
+ }
+ return await _dispatcher.ExecuteAsync(func, cancellation);
+ }
+
+ ///
+ public bool HasThreadAccess => _dispatcher.HasThreadAccess;
}
diff --git a/src/Uno.Extensions.Navigation.UI/Navigator.cs b/src/Uno.Extensions.Navigation.UI/Navigator.cs
index a6f51a32bb..ba5dcceec1 100644
--- a/src/Uno.Extensions.Navigation.UI/Navigator.cs
+++ b/src/Uno.Extensions.Navigation.UI/Navigator.cs
@@ -45,6 +45,15 @@ protected Navigator(
var regionUpdateId = RouteUpdater?.StartNavigation(Region) ?? Guid.Empty;
try
{
+
+ if (Dispatcher.HasThreadAccess &&
+ !request.InProgress)
+ {
+ request = request with { InProgress = true }; // Prevent multiple re-entrance where HasThreadAccess always returns true eg WASM
+ if (Logger.IsEnabled(LogLevel.Information)) Logger.LogInformationMessage($"Navigation started on UI thread, so moving to background thread");
+ return await Task.Run(() => NavigateAsync(request));
+ }
+
if (request.Source is null)
{
if (Logger.IsEnabled(LogLevel.Information)) Logger.LogInformationMessage($"Starting Navigation - Navigator: {this.GetType().Name} Request: {request.Route}");
diff --git a/src/Uno.Extensions.Navigation.UI/Navigators/PanelVisiblityNavigator.cs b/src/Uno.Extensions.Navigation.UI/Navigators/PanelVisiblityNavigator.cs
index d74c288d7b..4d13c908c5 100644
--- a/src/Uno.Extensions.Navigation.UI/Navigators/PanelVisiblityNavigator.cs
+++ b/src/Uno.Extensions.Navigation.UI/Navigators/PanelVisiblityNavigator.cs
@@ -99,27 +99,28 @@ protected override async Task RegionCanNavigate(Route route, RouteInfo? ro
return path;
}
- protected override Task PostNavigateAsync()
+ protected override async Task PostNavigateAsync()
{
if (Control is not null)
{
- foreach (var child in Control.Children.OfType())
+ await Dispatcher.ExecuteAsync(async cancellation =>
{
- if(child == CurrentlyVisibleControl)
+ foreach (var child in Control.Children.OfType())
{
- child.Opacity = 1;
- child.Visibility = Visibility.Visible;
- }
- else
- {
- child.Opacity = 0;
- child.Visibility = Visibility.Collapsed;
+ if (child == CurrentlyVisibleControl)
+ {
+ child.Opacity = 1;
+ child.Visibility = Visibility.Visible;
+ }
+ else
+ {
+ child.Opacity = 0;
+ child.Visibility = Visibility.Collapsed;
+ }
}
- }
+ });
}
-
- return Task.CompletedTask;
}
private FrameworkElement? FindByPath(string? path)
diff --git a/src/Uno.Extensions.Navigation/NavigationRequest.cs b/src/Uno.Extensions.Navigation/NavigationRequest.cs
index 068de8814f..24f27a10c3 100644
--- a/src/Uno.Extensions.Navigation/NavigationRequest.cs
+++ b/src/Uno.Extensions.Navigation/NavigationRequest.cs
@@ -4,6 +4,8 @@
public record NavigationRequest(object Sender, Route Route, CancellationToken? Cancellation = default, Type? Result = null, INavigator? Source = null)
#pragma warning restore SA1313 // Parameter names should begin with lower-case letter
{
+ internal bool InProgress { get; init; }
+
public override string ToString() => $"Request [Sender: {Sender.GetType().Name}, Route:{Route}, Result: {Result?.Name ?? "N/A"}]";
internal virtual IResponseNavigator? GetResponseNavigator(IResponseNavigatorFactory responseFactory, INavigator navigator) => default;
diff --git a/testing/TestHarness/Directory.Build.targets b/testing/TestHarness/Directory.Build.targets
index 0712cae045..b6ff508d83 100644
--- a/testing/TestHarness/Directory.Build.targets
+++ b/testing/TestHarness/Directory.Build.targets
@@ -34,4 +34,9 @@
+
+
+
diff --git a/testing/TestHarness/TestHarness-ui.slnf b/testing/TestHarness/TestHarness-ui.slnf
index bd035a1ba6..1a38851a44 100644
--- a/testing/TestHarness/TestHarness-ui.slnf
+++ b/testing/TestHarness/TestHarness-ui.slnf
@@ -8,6 +8,7 @@
"..\\..\\src\\Uno.Extensions.Authentication.UI\\Uno.Extensions.Authentication.UI.csproj",
"..\\..\\src\\Uno.Extensions.Authentication\\Uno.Extensions.Authentication.csproj",
"..\\..\\src\\Uno.Extensions.Configuration\\Uno.Extensions.Configuration.csproj",
+ "..\\..\\src\\Uno.Extensions.Core.Generators\\Uno.Extensions.Core.Generators.csproj",
"..\\..\\src\\Uno.Extensions.Core\\Uno.Extensions.Core.csproj",
"..\\..\\src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.UWP.Skia.csproj",
"..\\..\\src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.UWP.Wasm.csproj",
@@ -15,8 +16,8 @@
"..\\..\\src\\Uno.Extensions.Hosting\\Uno.Extensions.Hosting.csproj",
"..\\..\\src\\Uno.Extensions.Http.Refit\\Uno.Extensions.Http.Refit.csproj",
"..\\..\\src\\Uno.Extensions.Http\\Uno.Extensions.Http.csproj",
- "..\\..\\src\\Uno.Extensions.Localization\\Uno.Extensions.Localization.csproj",
"..\\..\\src\\Uno.Extensions.Localization.UI\\Uno.Extensions.Localization.UI.csproj",
+ "..\\..\\src\\Uno.Extensions.Localization\\Uno.Extensions.Localization.csproj",
"..\\..\\src\\Uno.Extensions.Logging.Serilog\\Uno.Extensions.Logging.Serilog.csproj",
"..\\..\\src\\Uno.Extensions.Logging\\Uno.Extensions.Logging.UWP.Skia.csproj",
"..\\..\\src\\Uno.Extensions.Logging\\Uno.Extensions.Logging.UWP.Wasm.csproj",
diff --git a/testing/TestHarness/TestHarness-winui.slnf b/testing/TestHarness/TestHarness-winui.slnf
index 1bc234818d..2b9df3f0a7 100644
--- a/testing/TestHarness/TestHarness-winui.slnf
+++ b/testing/TestHarness/TestHarness-winui.slnf
@@ -8,6 +8,7 @@
"..\\..\\src\\Uno.Extensions.Authentication.UI\\Uno.Extensions.Authentication.WinUI.csproj",
"..\\..\\src\\Uno.Extensions.Authentication\\Uno.Extensions.Authentication.csproj",
"..\\..\\src\\Uno.Extensions.Configuration\\Uno.Extensions.Configuration.csproj",
+ "..\\..\\src\\Uno.Extensions.Core.Generators\\Uno.Extensions.Core.Generators.csproj",
"..\\..\\src\\Uno.Extensions.Core\\Uno.Extensions.Core.csproj",
"..\\..\\src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.WinUI.Skia.csproj",
"..\\..\\src\\Uno.Extensions.Hosting.UI\\Uno.Extensions.Hosting.WinUI.Wasm.csproj",
@@ -15,8 +16,8 @@
"..\\..\\src\\Uno.Extensions.Hosting\\Uno.Extensions.Hosting.csproj",
"..\\..\\src\\Uno.Extensions.Http.Refit\\Uno.Extensions.Http.Refit.csproj",
"..\\..\\src\\Uno.Extensions.Http\\Uno.Extensions.Http.csproj",
- "..\\..\\src\\Uno.Extensions.Localization\\Uno.Extensions.Localization.csproj",
"..\\..\\src\\Uno.Extensions.Localization.UI\\Uno.Extensions.Localization.WinUI.csproj",
+ "..\\..\\src\\Uno.Extensions.Localization\\Uno.Extensions.Localization.csproj",
"..\\..\\src\\Uno.Extensions.Logging.Serilog\\Uno.Extensions.Logging.Serilog.csproj",
"..\\..\\src\\Uno.Extensions.Logging\\Uno.Extensions.Logging.WinUI.Skia.csproj",
"..\\..\\src\\Uno.Extensions.Logging\\Uno.Extensions.Logging.WinUI.Wasm.csproj",
diff --git a/testing/TestHarness/TestHarness.UITest/Constants.cs b/testing/TestHarness/TestHarness.UITest/Constants.cs
index db7bc9d198..2443c49665 100644
--- a/testing/TestHarness/TestHarness.UITest/Constants.cs
+++ b/testing/TestHarness/TestHarness.UITest/Constants.cs
@@ -4,7 +4,7 @@ namespace TestHarness.UITest;
public class Constants
{
- public readonly static string WebAssemblyDefaultUri = "https://localhost:51571";
+ public readonly static string WebAssemblyDefaultUri = "https://localhost:64052";
public readonly static string iOSAppName = "uno.platform.extensions.demo";
public readonly static string AndroidAppName = "uno.platform.extensions.demo";
public readonly static string iOSDeviceNameOrId = "iPad Pro (12.9-inch) (4th generation)";