共用方式為


原生內嵌

流覽範例。 流覽範例

一般而言,.NET 多平臺應用程式 UI (.NET MAUI) 應用程式包含包含版面配置的頁面,例如 Grid,以及包含檢視的版面配置,例如 Button。 頁面、版面配置和檢視全都衍生自 Element。 原生內嵌可讓衍生自 Element 的任何 .NET MAUI 控件在適用於 Android 的 .NET、適用於 iOS 的 .NET、適用於 Mac Catalyst 的 .NET 和 WinUI 原生應用程式中取用。

在原生應用程式中取用 .NET MAUI 控制件的程式如下所示:

  1. 建立擴充方法以啟動原生內嵌應用程式。 如需詳細資訊,請參閱 建立擴充方法
  2. 建立包含 .NET MAUI UI 和任何相依性的 .NET MAUI 單一專案。 如需詳細資訊,請參閱 建立 .NET MAUI 單一專案
  3. 建立原生應用程式,並在其中啟用 .NET MAUI 支援。 如需詳細資訊,請參閱 啟用 .NET MAUI 支援
  4. 在您的原生應用程式專案中初始化 .NET MAUI。 如需詳細資訊,請參閱 初始化 .NET MAUI
  5. 建立 .NET MAUI UI,並使用擴充方法將其轉換成適當的原生類型 ToPlatformEmbedding 。 如需詳細資訊,請參閱 取用 .NET MAUI 控件
  1. 建立包含 .NET MAUI UI 和任何相依性的 .NET MAUI 單一專案。 如需詳細資訊,請參閱 建立 .NET MAUI 單一專案
  2. 建立原生應用程式,並在其中啟用 .NET MAUI 支援。 如需詳細資訊,請參閱 啟用 .NET MAUI 支援
  3. 在您的原生應用程式專案中初始化 .NET MAUI。 如需詳細資訊,請參閱 初始化 .NET MAUI
  4. 建立 .NET MAUI UI,並使用擴充方法將其轉換成適當的原生類型 ToPlatformEmbedding 。 如需詳細資訊,請參閱 取用 .NET MAUI 控件

注意

使用原生內嵌時,.NET MAUI 的數據系結引擎仍可運作。 不過,頁面導覽必須使用原生導覽 API 來執行。

建立擴充方法

建立取用 .NET MAUI 控制件的原生應用程式之前,您應該先建立 .NET MAUI 類別庫專案,然後從中刪除 [平臺 ] 資料夾和 Class1 類別。 然後,將類別新增至包含下列程式代碼的 類別 EmbeddedExtensions

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>();
    }
}

這些擴充方法位於 命名空間中 Microsoft.Maui.Controls ,用來在每個平台上啟動原生內嵌應用程式。 擴充方法會參考 EmbeddedPlatformApplicationEmbeddedWindowHandlerEmbeddedWindowProvider 類型,您也必須新增至 .NET MAUI 連結庫專案。

下列程式代碼顯示 類別 EmbeddedPlatformApplication ,該類別應該新增至與 EmbeddedExtensions 類別相同的 .NET MAUI 連結庫專案:

#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);
    }
}

下列程式代碼顯示 類別 EmbeddedWindowHandler ,該類別應該新增至與 EmbeddedExtensions 類別相同的 .NET MAUI 連結庫專案:

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.");
}

下列程式代碼顯示 類別 EmbeddedWindowProvider ,該類別應該新增至與 EmbeddedExtensions 類別相同的 .NET MAUI 連結庫專案:

#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;
}

建立 .NET MAUI 單一專案

建立取用 .NET MAUI 控制件的原生應用程式之前,您應該將 .NET MAUI 應用程式專案新增至與您先前建立的 .NET MAUI 類別庫專案相同的解決方案。 .NET MAUI 應用程式項目會儲存您想要在原生內嵌應用程式中重複使用的 UI。 將新的 .NET MAUI 應用程式專案新增至方案之後,請執行下列步驟:

  1. 從專案刪除 Properties 資料夾。

  2. 從項目刪除 [平臺] 資料夾。

  3. 從項目刪除 Resources/AppIcon 資料夾。

  4. 從項目刪除 Resources/raw 資料夾。

  5. 從項目刪除 Resources/Splash 資料夾。

  6. 從項目刪除類別 AppShell

  7. 確定 類別 App 未設定 MainPage 屬性或覆寫 CreateWindow 方法:

    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }
    }
    
  8. 從項目刪除類別 MainPage

  9. 變更項目檔,讓 $(TargetFramework) 建置屬性設定為 net8.0,並 $(OutputType) 移除建置屬性:

    <PropertyGroup>
      <TargetFramework>net8.0</TargetFramework>
    
      <RootNamespace>MyMauiApp</RootNamespace>
      <UseMaui>true</UseMaui>
      <SingleProject>true</SingleProject>
      <ImplicitUsings>enable</ImplicitUsings>
      <Nullable>enable</Nullable>
    
      ...
    </PropertyGroup>
    

    重要

    請確定您設定 $(TargetFramework) 組建屬性,而不是$(TargetFrameworks) 建置屬性。

  10. CreateMauiApp修改 類別中的 MauiProgram 方法,使其接受在方法傳回之前叫用的選擇性Action<MauiAppBuilder>自變數:

    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();
    }
    

此時,您應該將所需的 .NET MAUI UI 新增至專案,包括任何相依性和資源,並確保專案正確建置。

建立 .NET MAUI 單一專案

建立取用 .NET MAUI 控制件的原生應用程式之前,您應該將 .NET MAUI 應用程式專案新增至與您先前建立的 .NET MAUI 類別庫專案相同的解決方案。 .NET MAUI 應用程式項目會儲存您想要在原生內嵌應用程式中重複使用的 UI。 將新的 .NET MAUI 應用程式專案新增至方案之後,請執行下列步驟:

  1. 從專案刪除 Properties 資料夾。

  2. 從項目刪除 [平臺] 資料夾。

  3. 從項目刪除 Resources/AppIcon 資料夾。

  4. 從項目刪除 Resources/raw 資料夾。

  5. 從項目刪除 Resources/Splash 資料夾。

  6. 從項目刪除類別 AppShell

  7. 確定 類別 App 未設定 MainPage 屬性或覆寫 CreateWindow 方法:

    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }
    }
    
  8. 從項目刪除類別 MainPage

  9. 變更項目檔,讓 $(TargetFramework) 建置屬性設定為 net9.0,並 $(OutputType) 移除建置屬性:

    <PropertyGroup>
      <TargetFramework>net9.0</TargetFramework>
    
      <RootNamespace>MyMauiApp</RootNamespace>
      <UseMaui>true</UseMaui>
      <SingleProject>true</SingleProject>
      <ImplicitUsings>enable</ImplicitUsings>
      <Nullable>enable</Nullable>
    
      ...
    </PropertyGroup>
    

    重要

    請確定您設定 $(TargetFramework) 組建屬性,而不是$(TargetFrameworks) 建置屬性。

  10. 在類別中MauiProgramCreateMauiApp,修改 方法以接受TApp泛型自變數,並接受在方法傳回之前叫用的選擇性Action<MauiAppBuilder>自變數。 此外,將呼叫從 UseMauiApp<App> 變更為 UseMauiEmbeddedApp<TApp>

    public static class MauiProgram
    {
        // Create a MauiApp using the specified application.
        public static MauiApp CreateMauiApp<TApp>(Action<MauiAppBuilder>? additional = null) where TApp : App
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiEmbeddedApp<TApp>()
                .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();
        }
    }
    
  11. 在類別中 MauiProgram ,新增 CreateMauiApp 可接受選擇性 Action<MauiAppBuilder> 自變數的多載:

    public static class MauiProgram
    {
        ...
    
        // Create a MauiApp using the default application.
        public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) =>
            CreateMauiApp<App>(additional);
    }
    

然後,您應該將所需的 .NET MAUI UI 新增至專案,包括任何相依性和資源,並確保專案正確建置。

啟用 .NET MAUI 支援

若要使用衍生自 Element .NET for Android 的 .NET、適用於 iOS 的 .NET、適用於 Mac Catalyst 的 .NET for Mac Catalyst 或 WinUI 應用程式,您應該將原生應用程式專案新增至與您先前建立之 .NET MAUI 類別庫專案相同的解決方案。 然後,您應該在原生應用程式的項目檔中啟用 .NET MAUI 支援,方法是在項目檔的第一個<PropertyGroup>節點中,將 和 $(MauiEnablePlatformUsings) 建置屬性設定$(UseMaui)true

<PropertyGroup>
    ...
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>

    <UseMaui>true</UseMaui>
    <MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>  
</PropertyGroup>

針對適用於 Mac Catalyst 應用程式的 .NET,您也必須將 build 屬性設定 $(SupportedOSPlatformVersion) 為至少 14.0:

<PropertyGroup>
    ...
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>

    <SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
    <UseMaui>true</UseMaui>
    <MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>  
</PropertyGroup>

針對適用於 Mac Catalyst 應用程式的 .NET,您也必須將組建屬性設定 $(SupportedOSPlatformVersion) 為至少 15.0:

<PropertyGroup>
    ...
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>

    <SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
    <UseMaui>true</UseMaui>
    <MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>  
</PropertyGroup>

針對 WinUI 應用程式,您必須將組建屬性設定 $(EnableDefaultXamlItems)false

<PropertyGroup>
    ...
    <Nullable>enable</Nullable>
    <ImplicitUsings>true</ImplicitUsings>

    <UseMaui>true</UseMaui>
    <MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>    
    <EnableDefaultXamlItems>false</EnableDefaultXamlItems>
</PropertyGroup>

這將會停止您收到已定義方法的 InitializeComponent 建置錯誤。

然後,將組建專案新增$(PackageReference)至 和 Microsoft.Maui.Controls.Compatiblity NuGet 套件的項目檔Microsoft.Maui.Controls

<ItemGroup>
    <PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
    <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>

然後,將組建專案新增 $(PackageReference) 至 NuGet 套件的項目檔 Microsoft.Maui.Controls

<ItemGroup>
    <PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
</ItemGroup>

初始化 .NET MAUI

必須先初始化 .NET MAUI,原生應用程式專案才能建構 .NET MAUI 控制件。 選擇何時初始化它主要取決於應用程式流程中最方便的時機 -- 它可以在啟動時執行,或在建構 .NET MAUI 控制項之前執行。 此處概述的方法是在建立應用程式的初始 UI 時初始化 .NET MAUI。

一般而言,在原生應用程式專案中初始化 .NET MAUI 的模式如下所示:

在Android上, OnCreate 類別中的 MainActivity 覆寫通常是執行應用程式啟動相關工作的位置。 下列程式代碼範例顯示類別中正在初始化的 MainActivity .NET MAUI:

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 context = UseWindowContext
            ? mauiApp.CreateEmbeddedWindowContext(this) // Create window context
            : new MauiContext(mauiApp.Services, this);  // Create app context

        ...              
    }
}

在 iOS 和 Mac Catalyst 上,應該修改 類別 AppDelegate 以傳回 trueFinishedLaunching 寫:

namespace MyNativeEmbeddedApp.iOS;

[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
    public override UIWindow? Window { get; set; }

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}

WillConnect接著,應該修改 類別中的 SceneDelegate 方法,以建立主要檢視控制器,並將其設定為的UINavigationController檢視:

namespace MyNativeEmbeddedApp.iOS;

[Register("SceneDelegate")]
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
    [Export("window")]
    public UIWindow? Window { get; set; }

    [Export("scene:willConnectToSession:options:")]
    public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
    {
        if (scene is not UIWindowScene windowScene)
            return;

        Window = new UIWindow(windowScene);

        var mainVC = new MainViewController();
        var navigationController = new UINavigationController(mainVC);
        navigationController.NavigationBar.PrefersLargeTitles = true;

        Window.RootViewController = navigationController;
        Window.MakeKeyAndVisible();
    }

    ...
}

然後,在 XML 編輯器中 ,開啟 Info.plist 檔案,並將下列 XML 新增至檔案結尾:

<key>UIApplicationSceneManifest</key>
<dict>
  <key>UIApplicationSupportsMultipleScenes</key>
  <true/>
  <key>UISceneConfigurations</key>
  <dict>
    <key>UIWindowSceneSessionRoleApplication</key>
    <array>
      <dict>
        <key>UISceneConfigurationName</key>
        <string>Default Configuration</string>
        <key>UISceneDelegateClassName</key>
        <string>SceneDelegate</string>
      </dict>
    </array>
  </dict>
</dict>

然後,您可以在主要檢視控制器的 ViewDidLoad 方法中初始化 .NET MAUI:

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 context = UseWindowContext
            ? mauiApp.CreateEmbeddedWindowContext(GetWindow()) // Create window context
            : new MauiContext(mauiApp.Services);               // Create app context

        ...
    }
}

在 Windows 上,類別 MainWindow 通常是執行 UI 相關應用程式啟動工作的地方:

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 context = UseWindowContext
            ? mauiApp.CreateEmbeddedWindowContext(this) // Create window context
            : new MauiContext(mauiApp.Services);        // Create app context

        ...
    }
}

在此範例中,會 MauiApp 使用延遲初始化來建立 物件。 擴充 UseMauiEmbedding 方法會在物件上 MauiAppBuilder 叫用。 因此,您的原生應用程式項目應該包含您建立的 .NET MAUI 類別庫項目的參考,其中包含這個擴充方法。 MauiContext然後,會從 MauiApp 物件建立 物件,並bool決定內容的範圍。 將 MauiContext .NET MAUI 控件轉換成原生類型時,將會使用 物件。

內嵌可以在應用程式內容或視窗內容中執行,但為了達到最大 .NET MAUI 相容性,它應該在視窗內容中執行。

應用程式內容

原生內嵌可以在應用程式內容中執行,而原生應用程式沒有視窗的知識。 使用這種方法,原生內嵌初始化需要您:

下列範例顯示此方法:

var mauiApp = MauiProgram.CreateMauiApp();
var context = new MauiContext(mauiApp.Services); // Activity also needs passing on Android

然後,可以使用擴充方法建立 .NET MAUI 檢視並轉換成原生檢視 ToPlatformEmbedded ,此方法需要 MauiContext 物件做為自變數。

此方法適用於原生應用程式需要內嵌簡單 .NET MAUI UI,但不需要存取所有 .NET MAUI 功能的案例。 這種方法的缺點是熱重載和某些 .NET MAUI 功能等工具將無法運作。

提示

MauiApp不建議每次將 .NET MAUI 檢視內嵌為原生檢視時建立物件。 如果內嵌檢視存取 屬性, Application.Current 這可能會有問題。 相反地, MauiApp 物件可以建立為共用的靜態實例:

public static class MyEmbeddedMauiApp
{
    static MauiApp? _shared;
    public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}

使用這種方法,您可以在應用程式生命週期早期具現化 MauiApp 物件,以避免第一次在應用程式中內嵌 .NET MAUI 檢視時發生小延遲。

在Android上,片段代表活動內UI的一部分。 下列程式代碼範例顯示片段中正在初始化的 .NET MAUI:

using Android.Runtime;
using Android.Views;
using AndroidX.Navigation.Fragment;
using Microsoft.Maui.Controls.Embedding;
using Fragment = AndroidX.Fragment.App.Fragment;
using View = Android.Views.View;

namespace MyNativeEmbeddedApp.Droid;

[Register("com.companyname.nativeembeddingdemo." + nameof(FirstFragment))]
public class FirstFragment : Fragment
{
    public override View? OnCreateView(LayoutInflater inflater, ViewGroup? container, Bundle? savedInstanceState) =>
        inflater.Inflate(Resource.Layout.fragment_first, container, false);

    public override void OnViewCreated(View view, Bundle? savedInstanceState)
    {
        base.OnViewCreated(view, savedInstanceState);

        // Ensure .NET MAUI app is built before creating .NET MAUI views
        var mauiApp = MyEmbeddedMauiApp.Shared;

        // Create .NET MAUI context
        var context = new MauiContext(mauiApp.Services, Activity);

        ...
    }
}

在 iOS 和 Mac Catalyst 上,應該修改 類別 AppDelegate 以傳回 trueFinishedLaunching 寫:

namespace MyNativeEmbeddedApp.iOS;

[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
    public override UIWindow? Window { get; set; }

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}

WillConnect接著,應該修改 類別中的 SceneDelegate 方法,以建立主要檢視控制器,並將其設定為的UINavigationController檢視:

namespace MyNativeEmbeddedApp.iOS;

[Register("SceneDelegate")]
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
    [Export("window")]
    public UIWindow? Window { get; set; }

    [Export("scene:willConnectToSession:options:")]
    public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
    {
        if (scene is not UIWindowScene windowScene)
            return;

        Window = new UIWindow(windowScene);

        var mainVC = new MainViewController();
        var navigationController = new UINavigationController(mainVC);
        navigationController.NavigationBar.PrefersLargeTitles = true;

        Window.RootViewController = navigationController;
        Window.MakeKeyAndVisible();
    }

    ...
}

然後,在 XML 編輯器中 ,開啟 Info.plist 檔案,並將下列 XML 新增至檔案結尾:

<key>UIApplicationSceneManifest</key>
<dict>
  <key>UIApplicationSupportsMultipleScenes</key>
  <true/>
  <key>UISceneConfigurations</key>
  <dict>
    <key>UIWindowSceneSessionRoleApplication</key>
    <array>
      <dict>
        <key>UISceneConfigurationName</key>
        <string>Default Configuration</string>
        <key>UISceneDelegateClassName</key>
        <string>SceneDelegate</string>
      </dict>
    </array>
  </dict>
</dict>

然後,您可以在主要檢視控制器的 ViewDidLoad 方法中初始化 .NET MAUI:

using Microsoft.Maui.Controls.Embedding;

namespace MyNativeEmbeddedApp.iOS;

public class MainViewController : UIViewController
{
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        // Ensure .NET MAUI app is built before creating .NET MAUI views
        var mauiApp = MyEmbeddedMauiApp.Shared;

        // Create .NET MAUI context
        var context = new MauiContext(mauiApp.Services);

        ...
    }
}

在 Windows 上,類別 MainWindow 通常是執行 UI 相關應用程式啟動工作的地方:

using Microsoft.Maui.Controls.Embedding;
using Microsoft.UI.Xaml;

namespace MyNativeEmbeddedApp.WinUI;

public sealed partial class MainWindow : Microsoft.UI.Xaml.Window
{
    public MainWindow()
    {
        this.InitializeComponent();
    }

    private async void OnRootLayoutLoaded(object? sender, RoutedEventArgs e)
    {
        await Task.Yield();

        // Ensure .NET MAUI app is built before creating .NET MAUI views
        var mauiApp = MyEmbeddedMauiApp.Shared;

        // Create .NET MAUI context
        var context = new MauiContext(mauiApp.Services);

        ...
    }
}

在此範例中,物件 MauiApp 會建立為共用的靜態實例。 建立這個物件時,會呼叫這個對象,MauiProgram.CreateMauiApp接著會在物件上MauiAppBuilder呼叫UseMauiEmbedding擴充方法。 因此,您的原生應用程式項目應該包含您建立的 .NET MAUI 類別庫項目的參考,其中包含您的 MauiProgram 類別和 .NET MAUI UI。 MauiContext然後,物件會從MauiApp物件建立,範圍設定為 MauiApp 物件。 將 MauiContext .NET MAUI 控件轉換成原生類型時,將會使用 物件。

窗口內容

原生內嵌可以在具有視窗知識的視窗內容中執行。 在某些情況下,.NET MAUI 檢視需要存取視窗才能正常運作。 例如,調適型觸發程式需要存取檢視的視窗,如果沒有視窗,則它們無法運作。

使用這種方法,原生內嵌初始化需要您:

  • 建立 MauiApp 物件。
  • 使用 CreateEmbeddedWindowContext 方法建立 MauiContext 物件。 對象 MauiContext 將用來從 .NET MAUI 檢視取得原生檢視。

方法 CreateEmbeddedWindowContext 會建立將原生視窗與 .NET MAUI 視窗建立關聯的視窗內容:

var mauiApp = MauiProgram.CreateMauiApp();
var context = mauiApp.CreateEmbeddedWindowContext(this);

然後,可以使用擴充方法建立 .NET MAUI 檢視並轉換成原生檢視 ToPlatformEmbedded ,此方法需要 MauiContext 物件做為自變數。

注意

擴充 ToPlatformEmbedded 方法具有多載,可將 .NET MAUI 檢視新增至內嵌視窗。

這種方法的優點是,每個原生視窗都有單一 .NET MAUI 視窗,視窗相關 API 會正常運作,而且熱重載等工具正常運作。

提示

MauiApp不建議每次將 .NET MAUI 檢視內嵌為原生檢視時建立物件。 如果內嵌檢視存取 屬性, Application.Current 這可能會有問題。 相反地, MauiApp 物件可以建立為共用的靜態實例:

public static class MyEmbeddedMauiApp
{
    static MauiApp? _shared;
    public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}

使用這種方法,您可以在應用程式生命週期早期具現化 MauiApp 物件,以避免第一次在應用程式中內嵌 .NET MAUI 檢視時發生小延遲。

在Android上,片段代表活動內UI的一部分。 下列程式代碼範例顯示片段中正在初始化的 .NET MAUI:

using Android.Runtime;
using Android.Views;
using AndroidX.Navigation.Fragment;
using Microsoft.Maui.Controls.Embedding;
using Fragment = AndroidX.Fragment.App.Fragment;
using View = Android.Views.View;

namespace MyNativeEmbeddedApp.Droid;

[Register("com.companyname.nativeembeddingdemo." + nameof(FirstFragment))]
public class FirstFragment : Fragment
{
    Activity? _window;
    IMauiContext? _windowContext;

    public IMauiContext WindowContext =>
        _windowContext ??= MyEmbeddedMauiApp.Shared.CreateEmbeddedWindowContext(_window ?? throw new InvalidOperationException());

    public override View? OnCreateView(LayoutInflater inflater, ViewGroup? container, Bundle? savedInstanceState) =>
        inflater.Inflate(Resource.Layout.fragment_first, container, false);

    public override void OnViewCreated(View view, Bundle? savedInstanceState)
    {
        base.OnViewCreated(view, savedInstanceState);

        _window ??= Activity;

        // Create MAUI embedded window context
        var context = WindowContext;

        ...
    }
}

在 iOS 和 Mac Catalyst 上,應該修改 類別 AppDelegate 以傳回 trueFinishedLaunching 寫:

namespace MyNativeEmbeddedApp.iOS;

[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
    public override UIWindow? Window { get; set; }

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}

WillConnect接著,應該修改 類別中的 SceneDelegate 方法,以建立主要檢視控制器,並將其設定為的UINavigationController檢視:

namespace MyNativeEmbeddedApp.iOS;

[Register("SceneDelegate")]
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
    [Export("window")]
    public UIWindow? Window { get; set; }

    [Export("scene:willConnectToSession:options:")]
    public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
    {
        if (scene is not UIWindowScene windowScene)
            return;

        Window = new UIWindow(windowScene);

        var mainVC = new MainViewController();
        var navigationController = new UINavigationController(mainVC);
        navigationController.NavigationBar.PrefersLargeTitles = true;

        Window.RootViewController = navigationController;
        Window.MakeKeyAndVisible();
    }

    ...
}

然後,在 XML 編輯器中 ,開啟 Info.plist 檔案,並將下列 XML 新增至檔案結尾:

<key>UIApplicationSceneManifest</key>
<dict>
  <key>UIApplicationSupportsMultipleScenes</key>
  <true/>
  <key>UISceneConfigurations</key>
  <dict>
    <key>UIWindowSceneSessionRoleApplication</key>
    <array>
      <dict>
        <key>UISceneConfigurationName</key>
        <string>Default Configuration</string>
        <key>UISceneDelegateClassName</key>
        <string>SceneDelegate</string>
      </dict>
    </array>
  </dict>
</dict>

然後,您可以在主要檢視控制器的 ViewDidLoad 方法中初始化 .NET MAUI:

using Microsoft.Maui.Controls.Embedding;

namespace MyNativeEmbeddedApp.iOS;

public class MainViewController : UIViewController
{
    UIKit.UIWindow? _window;
    IMauiContext? _windowContext;

    public IMauiContext WindowContext =>
        _windowContext ??= MyEmbeddedMauiApp.Shared.CreateEmbeddedWindowContext(_window ?? throw new InvalidOperationException());

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        _window ??= ParentViewController!.View!.Window;

        // Create MAUI embedded window context
        var context = WindowContext;

        ...
    }
}

在 Windows 上,類別 MainWindow 通常是執行 UI 相關應用程式啟動工作的地方:

using Microsoft.Maui.Controls.Embedding;
using Microsoft.UI.Xaml;

namespace MyNativeEmbeddedApp.WinUI;

public sealed partial class MainWindow : Microsoft.UI.Xaml.Window
{
    Microsoft.UI.Xaml.Window? _window;
    IMauiContext? _windowContext;

    public IMauiContext WindowContext =>
        _windowContext ??= MyEmbeddedMauiApp.Shared.CreateEmbeddedWindowContext(_window ?? throw new InvalidOperationException());

    public MainWindow()
    {
        this.InitializeComponent();
        _window ??= this;
    }

    private async void OnRootLayoutLoaded(object? sender, RoutedEventArgs e)
    {
        await Task.Yield();

        // Create MAUI embedded window context
        var context = WindowContext;

        ...
    }
}

在此範例中,物件 MauiApp 會建立為共用的靜態實例。 建立這個物件時,會呼叫這個對象,MauiProgram.CreateMauiApp接著會在物件上MauiAppBuilder呼叫UseMauiEmbedding擴充方法。 因此,您的原生應用程式項目應該包含您建立的 .NET MAUI 類別庫項目的參考,其中包含您的 MauiProgram 類別和 .NET MAUI UI。 MauiContext接著會使用 CreateEmbeddedWindowContext 方法建立 物件,範圍設定為視窗。 將 MauiContext .NET MAUI 控件轉換成原生類型時,將會使用 物件。

取用 .NET MAUI 控制件

在原生應用程式中初始化 .NET MAUI 之後,您可以將 .NET MAUI UI 新增至原生應用程式的版面配置。 建立UI的實例,並使用擴充方法將其轉換成適當的原生類型 ToPlatformEmbedded ,即可達成此目的。

在 Android 上,擴充方法會將 ToPlatformEmbedded .NET MAUI 控件轉換成 Android View 物件:

var mauiView = new MyMauiContent();
Android.Views.View nativeView = mauiView.ToPlatformEmbedded(context);

在此範例中, ContentView衍生物件會轉換成 Android View 物件。

注意

擴充 ToPlatformEmbedded 方法位於您稍早建立的 .NET MAUI 類別庫中。 因此,您的原生應用程式項目應該包含該專案的參考。

注意

擴充 ToPlatformEmbedded 方法位於 命名空間中 Microsoft.Maui.Controls.Embedding 。 因此,您的原生應用程式項目應該包含 using 該命名空間的語句。

View然後,物件可以新增至原生應用程式中的配置:

rootLayout.AddView(nativeView, new LinearLayout.LayoutParams(MatchParent, WrapContent));

在 iOS 和 Mac Catalyst 上,擴充 ToPlatformEmbedded 方法會將 .NET MAUI 控制件轉換成 UIView 物件:

var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);
nativeView.WidthAnchor.ConstraintEqualTo(View.Frame.Width).Active = true;
nativeView.HeightAnchor.ConstraintEqualTo(500).Active = true;

在此範例中, ContentView衍生物件會轉換成 UIView 物件,然後設定其寬度和高度條件約束以允許互動。

注意

擴充 ToPlatformEmbedded 方法位於您稍早建立的 .NET MAUI 類別庫中。 因此,您的原生應用程式項目應該包含該專案的參考。

UIView然後,物件可以新增至檢視控制器中的檢視:

stackView.AddArrangedSubView(nativeView);
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);

在此範例中, ContentView衍生物件會 UIView 轉換成 物件。

注意

擴充 ToPlatformEmbedded 方法位於 命名空間中 Microsoft.Maui.Controls.Embedding 。 因此,您的原生應用程式項目應該包含 using 該命名空間的語句。

UIView然後,物件可以新增至檢視控制器中的檢視:

stackView.AddArrangedSubView(new ContainerView(nativeView));

ContainerView 是包裝 .NET MAUI 檢視的自定義類型,以確保其大小正確。 這可藉由重新導向 IntrinsicContentSize 至 .NET MAUI 檢視的 SizeThatFits

class ContainerView : UIView
{
    public ContainerView(UIView view)
    {
        AddSubview(view);
    }

    public override CGSize IntrinsicContentSize =>
        SizeThatFits(new CGSize(nfloat.MaxValue, nfloat.MaxValue));

    public override CGSize SizeThatFits(CGSize size) =>
        Subviews?.FirstOrDefault()?.SizeThatFits(size) ?? CGSize.Empty;

    public override void LayoutSubviews()
    {
        if (Subviews?.FirstOrDefault() is { } view)
            view.Frame = Bounds;
    }

    public override void SetNeedsLayout()
    {
        base.SetNeedsLayout();
          InvalidateIntrinsicContentSize();
    }
}

此外, ToUIViewController .NET MAUI 中的擴充方法可以用來將 .NET MAUI 頁面轉換成 UIViewController

MyMauiPage myMauiPage = new MyMauiPage();
UIViewController myPageController = myMauiPage.ToUIViewController(context);

在這裡範例中, ContentPage衍生的物件會 UIViewController轉換成 。

在 Windows 上,擴充方法會將 ToPlatformEmbedded .NET MAUI 控件 FrameworkElement 轉換成 物件:

var mauiView = new MyMauiContent();
FrameworkElement nativeView = myMauiPage.ToPlatformEmbedded(context);

在此範例中, ContentView衍生物件會 FrameworkElement 轉換成 物件。 FrameworkElement然後可以將 物件設定為 WinUI 頁面的內容。

注意

擴充 ToPlatformEmbedded 方法位於您稍早建立的 .NET MAUI 類別庫中。 因此,您的原生應用程式項目應該包含該專案的參考。

注意

擴充 ToPlatformEmbedded 方法位於 命名空間中 Microsoft.Maui.Controls.Embedding 。 因此,您的原生應用程式項目應該包含 using 該命名空間的語句。

FrameworkElement然後,物件可以新增至原生應用程式中的配置:

stackPanel.Children.Add(nativeView);

重要

為了避免發生錯誤,在偵錯組態中執行原生內嵌應用程式之前,應該先停用 XAML 熱重載。

支援 XAML 熱重載

原生內嵌應用程式中不支援 XAML 熱重載。 不過,您仍然可以使用 XAML 熱重載,藉由建立取用 .NET MAUI UI 的 .NET MAUI 應用程式,快速逐一查看您的 .NET MAUI UI。

若要使用 XAML 熱重載來檢視 .NET MAUI UI:

  1. 在包含 .NET MAUI UI 的專案中,更新 MauiProgram 類別以新增 CreateMauiApp 多載,並修改現有的 CreateMauiApp 方法以接受泛型自變數:

    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) =>
            CreateMauiApp<App>(additional);
    
        public static MauiApp CreateMauiApp<TApp>(Action<MauiAppBuilder>? additional = null) where TApp : App
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<TApp>()
                .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();
        }
    }
    
  2. 在包含 .NET MAUI UI 的專案中,將每個資源字典從獨立 XAML 檔案轉換成程式代碼後置檔案所支援的資源字典。

  3. 在包含 .NET MAUI UI 的專案中,更新您的資源字典具現化,通常是在 App.xaml,讓 Source 屬性也會指定包含資源字典的元件:

    <ResourceDictionary Source="Resources/Styles/Colors.xaml;assembly=NativeEmbeddingDemo" />
    <ResourceDictionary Source="Resources/Styles/Styles.xaml;assembly=NativeEmbeddingDemo" />
    
  4. 建立新的 .NET MAUI 應用程式,並將其新增至包含 .NET MAUI UI 專案和原生內嵌應用程式的解決方案。

  5. 在您的 .NET MAUI 應用程式專案中,新增包含 .NET MAUI UI 之項目的參考。

  6. 在您的 .NET MAUI 應用程式專案中,刪除 .NET MAUI UI 專案提供資源的任何 資源 子資料夾。 例如,如果您的 .NET MAUI UI 專案包含資源字型資源>影像和資源>樣式資料夾,則應該從您剛才建立的 .NET MAUI 應用程式中刪除這些資料>夾。 這可讓您的 .NET MAUI 應用程式從包含 .NET MAUI UI 的專案取用資源。

  7. 在您的 .NET MAUI 應用程式中,更新類別 App ,使其衍生自 .NET MAUI UI 專案中的 App 類別:

    <myMauiUIProject:App xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                         xmlns:myMauiUIProject="clr-namespace:NativeEmbeddingDemo;assembly=NativeEmbeddingDemo"
                         x:Class="TestHarnessApp.TestApp">
        <myMauiUIProject:App.Resources>
            <!-- App specific resources go here -->
        </myMauiUIProject:App.Resources>
    </myMauiUIProject:App>
    

    然後更新 類別的程式代碼後置檔案 App ,使其衍生自 .NET MAUI UI 專案中的 App 類別,並從此專案載入任何 XAML 資源:

    public partial class TestApp : myMauiUIProject.App
    {
        public TestApp()
        {
            var baseResources = Resources;
            InitializeComponent();
            Resources.MergedDictionaries.Add(baseResources);
            MainPage = new HostPage();
        }
    }
    
  8. 在您的 .NET MAUI 應用程式中,新增頁面,以顯示包含 .NET MAUI UI 之專案的 UI:

    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:myMauiUIProject="clr-namespace:NativeEmbeddingDemo;assembly=NativeEmbeddingDemo"
                 x:Class="TestHarnessApp.HostPage"
                 Title="HostPage">
        <myMauiUIProject:MyMauiContent />
    </ContentPage>
    
  9. 在 .NET MAUI 應用程式中,更新 類別 MauiProgram ,以在包含 .NET MAUI UI 的專案中呼叫 CreateMauiApp 方法:

    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp() =>
            NativeEmbeddingDemo.MauiProgram.CreateMauiApp<TestApp>(builder =>
            {
                // Add any test harness configuration such as service stubs or mocks.
            });
    }
    

您現在應該能夠在每個平台上執行 .NET MAUI 應用程式專案,並使用 XAML 熱重載來逐一查看 .NET MAUI UI。

如需此方法的範例,請參閱 範例應用程式