Native Einbettung
Eine .NET Multiplatform App UI (.NET MAUI)-App umfasst in der Regel Seiten, die Layouts enthalten, wie Grid, und Layouts, die Ansichten enthalten, wie Button. Seiten, Layouts und Ansichten leiten sich alle von Element ab. Die native Einbettung ermöglicht die Verwendung aller .NET MAUI-Steuerelemente, die von Element abgeleitet werden, in .NET for Android-, .NET for iOS-, .NET for Mac Catalyst- und WinUI-nativen Apps.
Das Verfahren zur Verwendung eines .NET MAUI-Steuerelements in einer nativen App ist wie folgt:
- Erstellen Sie Erweiterungsmethoden, um Ihre systemeigene eingebettete App zu bootstrapen. Weitere Informationen finden Sie unter Erstellen von Erweiterungsmethoden.
- Erstellen Sie ein einzelnes .NET MAUI-Projekt, das Ihre .NET MAUI-Benutzeroberfläche und alle Abhängigkeiten enthält. Weitere Informationen finden Sie unter Erstellen eines einzelnen .NET MAUI-Projekts.
- Erstellen Sie eine systemeigene App und aktivieren Sie die .NET MAUI-Unterstützung darin. Weitere Informationen finden Sie unter Aktivieren der .NET MAUI-Unterstützung.
- Initialisieren Sie .NET MAUI durch Aufrufen der Erweiterungsmethode
UseMauiEmbedding
. Weitere Informationen finden Sie unter .NET MAUI initialisieren. - Erstellen Sie die .NET MAUI-Benutzeroberfläche und konvertieren Sie sie mit der Erweiterungsmethode
ToPlatformEmbedding
in den entsprechenden systemeigenen Typ. Weitere Informationen finden Sie unter Verwenden von .NET MAUI-Steuerelementen.
Hinweis
Bei Verwendung der nativen Einbettung funktioniert die Datenbindungsmaschine von .NET MAUI weiterhin. Die Seitennavigation muss jedoch über die native Navigations-API erfolgen.
Erstellen von Erweiterungsmethoden
Bevor Sie eine systemeigene App erstellen, die .NET MAUI-Steuerelemente verwendet, sollten Sie zuerst ein .NET MAUI-Klassenbibliotheksprojekt erstellen und den Ordner Plattformen und die Class1
-Klasse daraus löschen. Fügen Sie dann eine Klasse mit dem Namen EmbeddedExtensions
hinzu, die den folgenden Code enthält:
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Maui.Platform;
#if ANDROID
using PlatformView = Android.Views.View;
using PlatformWindow = Android.App.Activity;
using PlatformApplication = Android.App.Application;
#elif IOS || MACCATALYST
using PlatformView = UIKit.UIView;
using PlatformWindow = UIKit.UIWindow;
using PlatformApplication = UIKit.IUIApplicationDelegate;
#elif WINDOWS
using PlatformView = Microsoft.UI.Xaml.FrameworkElement;
using PlatformWindow = Microsoft.UI.Xaml.Window;
using PlatformApplication = Microsoft.UI.Xaml.Application;
#endif
namespace Microsoft.Maui.Controls;
public static class EmbeddedExtensions
{
public static MauiAppBuilder UseMauiEmbedding(this MauiAppBuilder builder, PlatformApplication? platformApplication = null)
{
#if ANDROID
platformApplication ??= (Android.App.Application)Android.App.Application.Context;
#elif IOS || MACCATALYST
platformApplication ??= UIKit.UIApplication.SharedApplication.Delegate;
#elif WINDOWS
platformApplication ??= Microsoft.UI.Xaml.Application.Current;
#endif
builder.Services.AddSingleton(platformApplication);
builder.Services.AddSingleton<EmbeddedPlatformApplication>();
builder.Services.AddScoped<EmbeddedWindowProvider>();
// Returning null is acceptable here as the platform window is optional - but we don't know until we resolve it
builder.Services.AddScoped<PlatformWindow>(svc => svc.GetRequiredService<EmbeddedWindowProvider>().PlatformWindow!);
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IMauiInitializeService, EmbeddedInitializeService>());
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(Window), typeof(EmbeddedWindowHandler));
});
return builder;
}
public static IMauiContext CreateEmbeddedWindowContext(this MauiApp mauiApp, PlatformWindow platformWindow, Window? window = null)
{
var windowScope = mauiApp.Services.CreateScope();
#if ANDROID
var windowContext = new MauiContext(windowScope.ServiceProvider, platformWindow);
#else
var windowContext = new MauiContext(windowScope.ServiceProvider);
#endif
window ??= new Window();
var wndProvider = windowContext.Services.GetRequiredService<EmbeddedWindowProvider>();
wndProvider.SetWindow(platformWindow, window);
window.ToHandler(windowContext);
return windowContext;
}
public static PlatformView ToPlatformEmbedded(this IElement element, IMauiContext context)
{
var wndProvider = context.Services.GetService<EmbeddedWindowProvider>();
if (wndProvider is not null && wndProvider.Window is Window wnd && element is VisualElement visual)
wnd.AddLogicalChild(visual);
return element.ToPlatform(context);
}
private class EmbeddedInitializeService : IMauiInitializeService
{
public void Initialize(IServiceProvider services) =>
services.GetRequiredService<EmbeddedPlatformApplication>();
}
}
Diese Erweiterungsmethoden befinden sich im Microsoft.Maui.Controls
-Namespace und werden verwendet, um Ihre systemeigene eingebettete App auf jeder Plattform zu bootstrapen. Die Erweiterungsmethoden verweisen auf die Typen EmbeddedPlatformApplication
, EmbeddedWindowHandler
und EmbeddedWindowProvider
, die Sie auch dem .NET MAUI-Bibliotheksprojekt hinzufügen müssen.
Der folgende Code zeigt die EmbeddedPlatformApplication
-Klasse, die dem gleichen .NET MAUI-Bibliotheksprojekt wie die EmbeddedExtensions
-Klasse hinzugefügt werden soll:
#if ANDROID
using PlatformApplication = Android.App.Application;
#elif IOS || MACCATALYST
using PlatformApplication = UIKit.IUIApplicationDelegate;
#elif WINDOWS
using PlatformApplication = Microsoft.UI.Xaml.Application;
#endif
namespace Microsoft.Maui.Controls;
internal class EmbeddedPlatformApplication : IPlatformApplication
{
private readonly MauiContext rootContext;
private readonly IMauiContext applicationContext;
public IServiceProvider Services { get; }
public IApplication Application { get; }
public EmbeddedPlatformApplication(IServiceProvider services)
{
IPlatformApplication.Current = this;
#if ANDROID
var platformApp = services.GetRequiredService<PlatformApplication>();
rootContext = new MauiContext(services, platformApp);
#else
rootContext = new MauiContext(services);
#endif
applicationContext = MakeApplicationScope(rootContext);
Services = applicationContext.Services;
Application = Services.GetRequiredService<IApplication>();
}
private static IMauiContext MakeApplicationScope(IMauiContext rootContext)
{
var scopedContext = new MauiContext(rootContext.Services);
InitializeScopedServices(scopedContext);
return scopedContext;
}
private static void InitializeScopedServices(IMauiContext scopedContext)
{
var scopedServices = scopedContext.Services.GetServices<IMauiInitializeScopedService>();
foreach (var service in scopedServices)
service.Initialize(scopedContext.Services);
}
}
Der folgende Code zeigt die EmbeddedWindowHandler
-Klasse, die dem gleichen .NET MAUI-Bibliotheksprojekt wie die EmbeddedExtensions
-Klasse hinzugefügt werden soll:
using Microsoft.Maui.Handlers;
#if ANDROID
using PlatformWindow = Android.App.Activity;
#elif IOS || MACCATALYST
using PlatformWindow = UIKit.UIWindow;
#elif WINDOWS
using PlatformWindow = Microsoft.UI.Xaml.Window;
#endif
namespace Microsoft.Maui.Controls;
internal class EmbeddedWindowHandler : ElementHandler<IWindow, PlatformWindow>, IWindowHandler
{
public static IPropertyMapper<IWindow, IWindowHandler> Mapper =
new PropertyMapper<IWindow, IWindowHandler>(ElementHandler.ElementMapper)
{
};
public static CommandMapper<IWindow, IWindowHandler> CommandMapper =
new CommandMapper<IWindow, IWindowHandler>(ElementHandler.ElementCommandMapper)
{
};
public EmbeddedWindowHandler() : base(Mapper)
{
}
protected override PlatformWindow CreatePlatformElement() =>
MauiContext!.Services.GetRequiredService<PlatformWindow>() ??
throw new InvalidOperationException("EmbeddedWindowHandler could not locate a platform window.");
}
Der folgende Code zeigt die EmbeddedWindowProvider
-Klasse, die dem gleichen .NET MAUI-Bibliotheksprojekt wie die EmbeddedExtensions
-Klasse hinzugefügt werden soll:
#if ANDROID
using PlatformWindow = Android.App.Activity;
#elif IOS || MACCATALYST
using PlatformWindow = UIKit.UIWindow;
#elif WINDOWS
using PlatformWindow = Microsoft.UI.Xaml.Window;
#endif
namespace Microsoft.Maui.Controls;
public class EmbeddedWindowProvider
{
WeakReference<PlatformWindow?>? platformWindow;
WeakReference<Window?>? window;
public PlatformWindow? PlatformWindow => Get(platformWindow);
public Window? Window => Get(window);
public void SetWindow(PlatformWindow? platformWindow, Window? window)
{
this.platformWindow = new WeakReference<PlatformWindow?>(platformWindow);
this.window = new WeakReference<Window?>(window);
}
private static T? Get<T>(WeakReference<T?>? weak) where T : class =>
weak is not null && weak.TryGetTarget(out var target) ? target : null;
}
Erstellen eines .NET MAUI-Einzelprojekts
Bevor Sie eine systemeigene App erstellen, die .NET MAUI-Steuerelemente verwendet, sollten Sie derselben Lösung wie das zuvor erstellte .NET MAUI-Klassenbibliotheksprojekt ein .NET MAUI-App-Projekt hinzufügen. Das .NET MAUI-App-Projekt speichert die Benutzeroberfläche, die Sie in Ihrer nativen eingebetteten App erneut verwenden möchten. Führen Sie nach dem Hinzufügen eines neuen .NET MAUI-App-Projekts zur Lösung die folgenden Schritte aus:
Löschen Sie den Ordner Eigenschaften aus dem Projekt.
Löschen Sie den Ordner Platforms aus dem Projekt.
Löschen Sie den Ordner Resources/AppIcon aus dem Projekt.
Löschen Sie den Ordner Resources/raw aus dem Projekt.
Löschen Sie den Ordner Resources/Splash aus dem Projekt.
Löschen Sie die
AppShell
-Klasse aus dem Projekt.Ändern Sie die
App
-Klasse so, dass sie dieMainPage
-Eigenschaft nicht festlegt:public partial class App : Application { public App() { InitializeComponent(); } }
Löschen Sie die
MainPage
-Klasse aus dem Projekt.Ändern Sie die Projektdatei so, dass die
$(TargetFrameworks)
-Buildeigenschaft aufnet8.0
festgelegt ist und die$(OutputType)
-Buildeigenschaft entfernt wird:<PropertyGroup> <TargetFrameworks>net8.0</TargetFrameworks> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
Ändern Sie die
CreateMauiApp
-Methode in derMauiProgram
-Klasse so, dass sie ein optionalesAction<MauiAppBuilder>
-Argument akzeptiert, das aufgerufen wird, bevor die Methode zurückgegeben wird:public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if DEBUG builder.Logging.AddDebug(); #endif additional?.Invoke(builder); return builder.Build(); }
An diesem Punkt sollten Sie die erforderliche .NET MAUI-Benutzeroberfläche zum Projekt hinzufügen, einschließlich aller Abhängigkeiten und Ressourcen, und stellen Sie sicher, dass das Projekt ordnungsgemäß erstellt wird.
Aktivieren der .NET MAUI-Unterstützung
Um .NET MAUI-Steuerelemente zu nutzen, die von Element in einer .NET for Android-, .NET for iOS-, .NET for Mac Catalyst- oder WinUI-App abgeleitet werden, sollten Sie Ihr systemeigenes App-Projekt zur gleichen Lösung wie das zuvor erstellte .NET MAUI-Klassenbibliotheksprojekt hinzufügen. Anschließend sollten Sie die .NET MAUI-Unterstützung in der Projektdatei Ihrer nativen App aktivieren, indem Sie die $(UseMaui)
- und $(MauiEnablePlatformUsings)
-Buildeigenschaften im ersten <PropertyGroup>
-Knoten in der Projektdatei auf true
festlegen:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Für .NET for Mac Catalyst-Apps müssen Sie auch die $(SupportedOSPlatformVersion)
-Buildeigenschaft auf mindestens 14.0 festlegen:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Für WinUI-Apps müssen Sie auch die $(EnableDefaultXamlItems)
-Buildeigenschaft auf false
festlegen:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
<EnableDefaultXamlItems>false</EnableDefaultXamlItems>
</PropertyGroup>
Dadurch wird verhindert, dass Sie Build-Fehler erhalten, weil die Methode InitializeComponent
bereits definiert ist.
Fügen Sie dann $(PackageReference)
-Buildelemente zur Projektdatei für die Microsoft.Maui.Controls
- und Microsoft.Maui.Controls.Compatiblity
-NuGet-Pakete hinzu:
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>
Initialisieren von .NET MAUI
.NET MAUI muss initialisiert werden, bevor ein natives App-Projekt ein .NET MAUI-Steuerelement konstruieren kann. Die Auswahl, wann sie initialisiert werden soll, hängt in erster Linie davon ab, wann sie in Ihrem App-Flow am passendsten ist – sie kann beim Start oder direkt vor dem Erstellen eines .NET MAUI-Steuerelements ausgeführt werden. Der hier beschriebene Ansatz besteht darin, .NET MAUI zu initialisieren, wenn die anfängliche Benutzeroberfläche der App erstellt wird.
In der Regel lautet das Muster für die Initialisierung von .NET MAUI in einem systemeigenen App-Projekt wie folgt:
- Erstellen eines MauiApp-Objekts
- Erstellen Sie ein MauiContext-Objekt aus dem MauiApp-Objekt.
Unter Android ist die OnCreate
-Überschreibung in der MainActivity
-Klasse normalerweise der Ort, an dem Aufgaben im Zusammenhang mit dem App-Start ausgeführt werden. Das folgende Codebeispiel zeigt die Initialisierung von .NET MAUI in der Klasse MainActivity
:
namespace MyNativeEmbeddedApp.Droid
{
[Activity(Label = "@string/app_name", MainLauncher = true, Theme = "@style/AppTheme")]
public class MainActivity : Activity
{
public static readonly Lazy<MauiApp> MauiApp = new(() =>
{
var mauiApp = MauiProgram.CreateMauiApp(builder =>
{
builder.UseMauiEmbedding();
});
return mauiApp;
});
public static bool UseWindowContext = true;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MainActivity.MauiApp.Value;
// Create .NET MAUI context
var mauiContext = UseWindowContext
? mauiApp.CreateEmbeddedWindowContext(this) // Create window context
: new MauiContext(mauiApp.Services, this); // Create app context
...
}
}
}
Unter iOS und Mac Catalyst sollte die FinishedLaunching
-Außerkraftsetzung in der AppDelegate
-Klasse geändert werden, um ihren Hauptansichtscontroller zu erstellen:
namespace MyNativeEmbeddedApp.iOS
{
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var vc = new MainViewController();
Window.RootViewController = vc;
Window.MakeKeyAndVisible();
return true;
}
}
}
.NET MAUI kann dann in der ViewDidLoad
-Methode im Hauptansichtscontroller initialisiert werden:
using Microsoft.Maui.Platform;
namespace MyNativeEmbeddedApp.iOS
{
public class MainViewController : UIViewController
{
UIWindow GetWindow() =>
View?.Window ??
ParentViewController?.View?.Window ??
MainViewController.MauiApp.Value.Services.GetRequiredService<IUIApplicationDelegate>().GetWindow() ??
UIApplication.SharedApplication.Delegate.GetWindow();
public static readonly Lazy<MauiApp> MauiApp = new(() =>
{
var mauiApp = MauiProgram.CreateMauiApp(builder =>
{
builder.UseMauiEmbedding();
});
return mauiApp;
});
public static bool UseWindowContext = true;
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Ensure app is built before creating .NET MAUI views
var mauiApp = MainViewController.MauiApp.Value;
// Create .NET MAUI context
var mauiContext = UseWindowContext
? mauiApp.CreateEmbeddedWindowContext(GetWindow()) // Create window context
: new MauiContext(mauiApp.Services); // Create app context
...
}
}
}
Unter Windows ist die MainWindow
-Klasse in der Regel der Ort, an dem auf die Benutzeroberfläche bezogene Startaufgaben der App ausgeführt werden:
namespace MyNativeEmbeddedApp.WinUI
{
public sealed partial class MainWindow : Microsoft.UI.Xaml.Window
{
public static readonly Lazy<MauiApp> MauiApp = new(() =>
{
var mauiApp = MauiProgram.CreateMauiApp(builder =>
{
builder.UseMauiEmbedding();
});
return mauiApp;
});
public static bool UseWindowContext = true;
public MainWindow()
{
this.InitializeComponent();
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MainWindow.MauiApp.Value;
// Create .NET MAUI context
var mauiContext = UseWindowContext
? mauiApp.CreateEmbeddedWindowContext(this) // Create window context
: new MauiContext(mauiApp.Services); // Create app context
...
}
}
}
In diesem Beispiel wird das MauiApp-Objekt mithilfe der verzögerten Initialisierung erstellt. Die UseMauiEmbedding
-Erweiterungsmethode wird für das MauiAppBuilder-Objekt aufgerufen. Daher sollte Ihr systemeigenes App-Projekt einen Verweis auf das .NET MAUI-Klassenbibliotheksprojekt enthalten, das Sie erstellt haben, das diese Erweiterungsmethode enthält. Anschließend wird ein MauiContext-Objekt aus dem MauiApp-Objekt erstellt, wobei bool
bestimmt, wo sich der Kontext befindet. Das MauiContext-Objekt wird bei der Konvertierung von .NET MAUI-Steuerelementen in native Typen verwendet.
Verwenden von .NET MAUI-Steuerelementen
Nachdem .NET MAUI in Ihrer nativen App initialisiert wurde, können Sie die .NET MAUI-Benutzeroberfläche zum Layout Ihrer nativen App hinzufügen. Dies kann erreicht werden, indem eine Instanz der Benutzeroberfläche erstellt und mit der Erweiterungsmethode ToPlatformEmbedded
in den entsprechenden nativen Typ konvertiert wird.
Unter Android konvertiert die ToPlatformEmbedded
-Erweiterungsmethode das .NET MAUI-Steuerelement in ein Android-View-Objekt:
var mauiView = new MyMauiContent();
Android.Views.View nativeView = mauiView.ToPlatformEmbedded(mauiContext);
In diesem Beispiel wird ein ContentView-abgeleitetes Objekt in ein Android View-Objekt umgewandelt.
Hinweis
Die Erweiterungsmethode ToPlatformEmbedded
befindet sich in der .NET MAUI-Klassenbibliothek, die Sie zuvor erstellt haben. Daher sollte Ihr systemeigenes App-Projekt einen Verweis auf dieses Projekt enthalten.
Das View-Objekt kann dann einem Layout in Ihrer nativen App hinzugefügt werden:
rootLayout.AddView(nativeView, new LinearLayout.LayoutParams(MatchParent, WrapContent));
Unter iOS und Mac Catalyst konvertiert die Erweiterungsmethode ToPlatformEmbedded
das .NET MAUI-Steuerelement in ein UIView-Objekt:
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(mauiContext);
nativeView.WidthAnchor.ConstraintEqualTo(View.Frame.Width).Active = true;
nativeView.HeightAnchor.ConstraintEqualTo(500).Active = true;
In diesem Beispiel wird ein von ContentView abgeleitetes Objekt in ein UIView-Objekt konvertiert. Anschließend werden die Einschränkungen für Breite und Höhe festgelegt, um die Interaktion zu ermöglichen.
Hinweis
Die Erweiterungsmethode ToPlatformEmbedded
befindet sich in der .NET MAUI-Klassenbibliothek, die Sie zuvor erstellt haben. Daher sollte Ihr systemeigenes App-Projekt einen Verweis auf dieses Projekt enthalten.
Das UIView-Objekt kann dann zu einer Ansicht im Ansichtscontroller hinzugefügt werden:
stackView.AddArrangedSubView(nativeView);
Darüber hinaus kann eine ToUIViewController
-Erweiterungsmethode in .NET MAUI verwendet werden, um zu versuchen, eine .NET MAUI-Seite in eine UIViewController umzuwandeln:
MyMauiPage myMauiPage = new MyMauiPage();
UIViewController myPageController = myMauiPage.ToUIViewController(mauiContext);
In diesem Beispiel wird ein ContentPage-abgeleitetes Objekt in ein UIViewController umgewandelt.
Unter Windows konvertiert die ToPlatformEmbedded
-Erweiterungsmethode das .NET MAUI-Steuerelement in ein FrameworkElement
-Objekt:
var mauiView = new MyMauiContent();
FrameworkElement nativeView = myMauiPage.ToPlatformEmbedded(mauiContext);
In diesem Beispiel wird ein ContentView-abgeleitetes Objekt in ein FrameworkElement
-Objekt umgewandelt. Das FrameworkElement
-Objekt kann dann als Inhalt einer WinUI-Seite festgelegt werden.
Das FrameworkElement
-Objekt kann dann einem Layout in Ihrer nativen App hinzugefügt werden:
stackPanel.Children.Add(nativeView);
Wichtig
Um einen Fehler zu vermeiden, sollte das erneute Laden von XAML deaktiviert werden, bevor eine native eingebettete App in der Debugkonfiguration ausgeführt wird.
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für