Skip to content

Commit

Permalink
Merge pull request #1809 from unoplatform/mergify/bp/legacy/2x/pr-1806
Browse files Browse the repository at this point in the history
Initializing Application Window and Main Page (backport #1806)
  • Loading branch information
nickrandolph authored Aug 25, 2023
2 parents 1de9916 + 48d3c02 commit 8a92f5a
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 22 deletions.
2 changes: 1 addition & 1 deletion samples/MauiEmbedding/MauiEmbedding/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ protected async override void OnLaunched(LaunchActivatedEventArgs args)
var builder = this.CreateBuilder(args)
// Add navigation support for toolkit controls such as TabBar and NavigationView
.UseToolkitNavigation()
.UseMauiEmbedding<MauiControls.App>(maui => maui.UseCustomLibrary())
.Configure(host => host
#if DEBUG
// Switch to Development environment when running in DEBUG
Expand Down Expand Up @@ -61,7 +62,6 @@ protected async override void OnLaunched(LaunchActivatedEventArgs args)
// TODO: Register your services
//services.AddSingleton<IMyService, MyService>();
})
.UseMauiEmbedding<MauiControls.App>(this, maui => maui.UseCustomLibrary())
.UseNavigation(RegisterRoutes)
);
MainWindow = builder.Window;
Expand Down
14 changes: 14 additions & 0 deletions src/Uno.Extensions.Maui.UI/Internals/EmbeddedWindowHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Uno.Extensions.Maui.Internals;

internal class EmbeddedWindowHandler : IElementHandler
{
public object? PlatformView { get; set; }
public IElement? VirtualView { get; set; }
public IMauiContext? MauiContext { get; set; }

public void DisconnectHandler() { }
public void Invoke(string command, object? args = null) { }
public void SetMauiContext(IMauiContext mauiContext) => MauiContext = mauiContext;
public void SetVirtualView(IElement view) => VirtualView = view;
public void UpdateValue(string property) { }
}
1 change: 1 addition & 0 deletions src/Uno.Extensions.Maui.UI/MauiEmbedding.android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ private static void InitializeMauiEmbeddingApp(this MauiApp mauiApp, Application
Microsoft.Maui.ApplicationModel.Platform.Init(androidApp);

androidApp.SetApplicationHandler(iApp, rootContext);
InitializeApplicationMainPage(iApp);
}
}
5 changes: 3 additions & 2 deletions src/Uno.Extensions.Maui.UI/MauiEmbedding.apple.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using UIKit;
using UIKit;
using Uno.Extensions.Maui.Platform;

namespace Uno.Extensions.Maui;
Expand Down Expand Up @@ -26,8 +26,9 @@ private static void InitializeMauiEmbeddingApp(this MauiApp mauiApp, Application
throw new MauiEmbeddingException(Properties.Resources.TheApplicationMustInheritFromEmbeddingApplication);
}

// TODO: Evaluate getting the Root View Controller for a Platform.Init for Maui
Microsoft.Maui.ApplicationModel.Platform.Init(() => app.Window!.RootViewController!);
embeddingApp.InitializeApplication(mauiApp.Services, iApp);
app.SetApplicationHandler(iApp, rootContext);
InitializeApplicationMainPage(iApp);
}
}
99 changes: 80 additions & 19 deletions src/Uno.Extensions.Maui.UI/MauiEmbedding.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Maui;
using Uno.Extensions.Hosting;

namespace Uno.Extensions.Maui;

Expand All @@ -13,59 +13,74 @@ public static partial class MauiEmbedding
/// </summary>
/// <returns>The updated app builder.</returns>
/// <param name="builder">The IHost builder.</param>
/// <param name="app">The Uno app.</param>
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static IHostBuilder UseMauiEmbedding(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Action<MauiAppBuilder>? configure = null) =>
builder.UseMauiEmbedding<MauiApplication>(app, configure);
public static IApplicationBuilder UseMauiEmbedding(this IApplicationBuilder builder, Action<MauiAppBuilder>? configure = null) =>
builder.UseMauiEmbedding<MauiApplication>(configure);

/// <summary>
/// Registers Maui embedding in the Uno Platform app builder.
/// </summary>
/// <returns>The updated app builder.</returns>
/// <param name="builder">The IHost builder.</param>
/// <param name="app">The Uno app.</param>
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static IHostBuilder UseMauiEmbedding<TApp>(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Action<MauiAppBuilder>? configure = null)
public static IApplicationBuilder UseMauiEmbedding<TApp>(this IApplicationBuilder builder, Action<MauiAppBuilder>? configure = null)
where TApp : MauiApplication
{
app.UseMauiEmbedding<TApp>(configure);
builder.App.UseMauiEmbedding<TApp>(builder.Window, configure);
return builder;
}

private class MauiHostProviderFactory : IServiceProviderFactory<IServiceProvider>
{
public IServiceProvider CreateBuilder(IServiceCollection services) => services.BuildServiceProvider();
public IServiceProvider CreateServiceProvider(IServiceProvider containerBuilder) => containerBuilder;
}
/// <summary>
/// Registers Maui embedding in the Uno Platform app builder.
/// </summary>
/// <returns>The updated app builder.</returns>
/// <param name="builder">The IHost builder.</param>
/// <param name="app">The Uno app.</param>
/// <param name="window">The Main Application Window.</param>
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static IHostBuilder UseMauiEmbedding(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action<MauiAppBuilder>? configure = null) =>
builder.UseMauiEmbedding<MauiApplication>(app, window, configure);

private class UnoHostProviderFactory : IServiceProviderFactory<IServiceCollection>
/// <summary>
/// Registers Maui embedding in the Uno Platform app builder.
/// </summary>
/// <returns>The updated app builder.</returns>
/// <param name="builder">The IHost builder.</param>
/// <param name="app">The Uno app.</param>
/// <param name="window">The Main Application Window.</param>
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static IHostBuilder UseMauiEmbedding<TApp>(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action<MauiAppBuilder>? configure = null)
where TApp : MauiApplication
{
public IServiceCollection CreateBuilder(IServiceCollection services) => throw new NotImplementedException();
public IServiceProvider CreateServiceProvider(IServiceCollection containerBuilder) => containerBuilder.BuildServiceProvider();
app.UseMauiEmbedding<TApp>(window, configure);
return builder;
}

/// <summary>
/// Registers Maui embedding with WinUI3 and WPF application builder.
/// </summary>
/// <param name="app">The Uno app.</param>
/// <param name="window">The Main Application Window.</param>
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static Microsoft.UI.Xaml.Application UseMauiEmbedding(this Microsoft.UI.Xaml.Application app, Action<MauiAppBuilder>? configure = null) =>
app.UseMauiEmbedding<MauiApplication>(configure);
public static Microsoft.UI.Xaml.Application UseMauiEmbedding(this Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action<MauiAppBuilder>? configure = null) =>
app.UseMauiEmbedding<MauiApplication>(window, configure);

/// <summary>
/// Registers Maui embedding with WinUI3 and WPF application builder.
/// </summary>
/// <param name="app">The Uno app.</param>
/// <param name="window">The Main Application Window.</param>
/// <param name="configure">Optional lambda to configure the Maui app builder.</param>
public static Microsoft.UI.Xaml.Application UseMauiEmbedding<TApp>(this Microsoft.UI.Xaml.Application app, Action<MauiAppBuilder>? configure = null)
public static Microsoft.UI.Xaml.Application UseMauiEmbedding<TApp>(this Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action<MauiAppBuilder>? configure = null)
where TApp : MauiApplication
{
#if MAUI_EMBEDDING
var mauiAppBuilder = MauiApp.CreateBuilder()
.UseMauiEmbedding<TApp>()
.RegisterPlatformServices(app);

mauiAppBuilder.Services.AddSingleton<Microsoft.UI.Xaml.Application>(_ => app)
mauiAppBuilder.Services.AddSingleton(app)
.AddSingleton(window)
.AddSingleton<IMauiInitializeService, MauiEmbeddingInitializer>();

// HACK: https://github.com/dotnet/maui/pull/16758
Expand All @@ -80,6 +95,8 @@ public static Microsoft.UI.Xaml.Application UseMauiEmbedding<TApp>(this Microsof
return app;
}

#if MAUI_EMBEDDING

private static void InitializeScopedServices(this IMauiContext scopedContext)
{
var scopedServices = scopedContext.Services.GetServices<IMauiInitializeScopedService>();
Expand All @@ -90,6 +107,50 @@ private static void InitializeScopedServices(this IMauiContext scopedContext)
}
}

private static void InitializeApplicationMainPage(IApplication iApp)
{
if (iApp is not MauiApplication app || app.Handler?.MauiContext is null)
{
// NOTE: This method is supposed to be called immediately after we initialize the Application Handler
// This should never actually happen but is required due to nullability
return;
}

var context = app.Handler.MauiContext;

// Create an Application Main Page and initialize a Handler with the Maui Context
var page = new ContentPage();
app.MainPage = page;
_ = page.ToPlatform(context);

// Create a Maui Window and initialize a Handler shim. This will expose the actual Application Window
var virtualWindow = new Microsoft.Maui.Controls.Window(page);
virtualWindow.Handler = new EmbeddedWindowHandler
{
#if IOS || MACCATALYST
PlatformView = context.Services.GetRequiredService<Microsoft.UI.Xaml.Application>().Window,
#elif ANDROID
PlatformView = context.Services.GetRequiredService<Android.App.Activity>(),
#elif WINDOWS
PlatformView = context.Services.GetRequiredService<Microsoft.UI.Xaml.Window>(),
#endif
VirtualView = virtualWindow,
MauiContext = context
};

app.SetCoreWindow(virtualWindow);
}

private static void SetCoreWindow(this IApplication app, Microsoft.Maui.Controls.Window window)
{
if(app.Windows is List<Microsoft.Maui.Controls.Window> windows)
{
windows.Add(window);
}
}

#endif

// NOTE: This was part of the POC and is out of scope for the MVP. Keeping it in case we want to add it back later.
/*
public static MauiAppBuilder MapControl<TWinUI, TMaui>(this MauiAppBuilder builder)
Expand Down
1 change: 1 addition & 0 deletions src/Uno.Extensions.Maui.UI/MauiEmbedding.windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ private static void InitializeMauiEmbeddingApp(this MauiApp mauiApp, Application

embeddingApp.InitializeApplication(mauiApp.Services, iApp);
app.SetApplicationHandler(iApp, rootContext);
InitializeApplicationMainPage(iApp);
}
}
6 changes: 6 additions & 0 deletions src/Uno.Extensions.Maui.UI/MauiHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ public MauiHost()
DataContextChanged += OnDataContextChanged;
Unloaded += OnMauiContentUnloaded;
ActualThemeChanged += OnActualThemeChanged;
SizeChanged += OnSizeChanged;
}

private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
VisualElement?.PlatformSizeChanged();
}

private void OnActualThemeChanged(FrameworkElement sender, object args)
Expand Down
4 changes: 4 additions & 0 deletions src/Uno.Extensions.Maui.UI/Uno.Extensions.Maui.WinUI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
<None Include="MauiThickness.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Uno.Extensions.Hosting.UI\Uno.Extensions.Hosting.WinUI.csproj" />
</ItemGroup>

<Choose>
<When Condition="$(IsMauiEmbedding)">
<PropertyGroup>
Expand Down

0 comments on commit 8a92f5a

Please sign in to comment.