原生內嵌
一般而言,.NET 多平臺應用程式 UI (.NET MAUI) 應用程式包含包含版面配置的頁面,例如 Grid,以及包含檢視的版面配置,例如 Button。 頁面、版面配置和檢視全都衍生自 Element。 原生內嵌可讓衍生自 Element 的任何 .NET MAUI 控件在適用於 Android 的 .NET、適用於 iOS 的 .NET、適用於 Mac Catalyst 的 .NET 和 WinUI 原生應用程式中取用。
在原生應用程式中取用 .NET MAUI 控制件的程式如下所示:
- 建立擴充方法以啟動原生內嵌應用程式。 如需詳細資訊,請參閱 建立擴充方法。
- 建立包含 .NET MAUI UI 和任何相依性的 .NET MAUI 單一專案。 如需詳細資訊,請參閱 建立 .NET MAUI 單一專案。
- 建立原生應用程式,並在其中啟用 .NET MAUI 支援。 如需詳細資訊,請參閱 啟用 .NET MAUI 支援。
- 在您的原生應用程式專案中初始化 .NET MAUI。 如需詳細資訊,請參閱 初始化 .NET MAUI。
- 建立 .NET MAUI UI,並使用擴充方法將其轉換成適當的原生類型
ToPlatformEmbedding
。 如需詳細資訊,請參閱 取用 .NET MAUI 控件。
- 建立包含 .NET MAUI UI 和任何相依性的 .NET MAUI 單一專案。 如需詳細資訊,請參閱 建立 .NET MAUI 單一專案。
- 建立原生應用程式,並在其中啟用 .NET MAUI 支援。 如需詳細資訊,請參閱 啟用 .NET MAUI 支援。
- 在您的原生應用程式專案中初始化 .NET MAUI。 如需詳細資訊,請參閱 初始化 .NET MAUI。
- 建立 .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
,用來在每個平台上啟動原生內嵌應用程式。 擴充方法會參考 EmbeddedPlatformApplication
、 EmbeddedWindowHandler
和 EmbeddedWindowProvider
類型,您也必須新增至 .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 應用程式專案新增至方案之後,請執行下列步驟:
從專案刪除 Properties 資料夾。
從項目刪除 [平臺] 資料夾。
從項目刪除 Resources/AppIcon 資料夾。
從項目刪除 Resources/raw 資料夾。
從項目刪除 Resources/Splash 資料夾。
從項目刪除類別
AppShell
。確定 類別
App
未設定MainPage
屬性或覆寫CreateWindow
方法:public partial class App : Application { public App() { InitializeComponent(); } }
從項目刪除類別
MainPage
。變更項目檔,讓
$(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)
建置屬性。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 應用程式專案新增至方案之後,請執行下列步驟:
從專案刪除 Properties 資料夾。
從項目刪除 [平臺] 資料夾。
從項目刪除 Resources/AppIcon 資料夾。
從項目刪除 Resources/raw 資料夾。
從項目刪除 Resources/Splash 資料夾。
從項目刪除類別
AppShell
。確定 類別
App
未設定MainPage
屬性或覆寫CreateWindow
方法:public partial class App : Application { public App() { InitializeComponent(); } }
從項目刪除類別
MainPage
。變更項目檔,讓
$(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)
建置屬性。在類別中
MauiProgram
CreateMauiApp
,修改 方法以接受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(); } }
在類別中
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 的模式如下所示:
- 建立 MauiApp 物件。
- 從 MauiApp 物件建立 MauiContext 物件。 對象 MauiContext 將用來從 .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
以傳回 true
覆 FinishedLaunching
寫:
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 相容性,它應該在視窗內容中執行。
應用程式內容
原生內嵌可以在應用程式內容中執行,而原生應用程式沒有視窗的知識。 使用這種方法,原生內嵌初始化需要您:
- 建立 MauiApp 物件。
- 從 MauiApp 物件建立 MauiContext 物件。 對象 MauiContext 將用來從 .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
以傳回 true
覆 FinishedLaunching
寫:
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
以傳回 true
覆 FinishedLaunching
寫:
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:
在包含 .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(); } }
在包含 .NET MAUI UI 的專案中,將每個資源字典從獨立 XAML 檔案轉換成程式代碼後置檔案所支援的資源字典。
在包含 .NET MAUI UI 的專案中,更新您的資源字典具現化,通常是在 App.xaml 中,讓
Source
屬性也會指定包含資源字典的元件:<ResourceDictionary Source="Resources/Styles/Colors.xaml;assembly=NativeEmbeddingDemo" /> <ResourceDictionary Source="Resources/Styles/Styles.xaml;assembly=NativeEmbeddingDemo" />
建立新的 .NET MAUI 應用程式,並將其新增至包含 .NET MAUI UI 專案和原生內嵌應用程式的解決方案。
在您的 .NET MAUI 應用程式專案中,新增包含 .NET MAUI UI 之項目的參考。
在您的 .NET MAUI 應用程式專案中,刪除 .NET MAUI UI 專案提供資源的任何 資源 子資料夾。 例如,如果您的 .NET MAUI UI 專案包含資源字型、資源>影像和資源>樣式資料夾,則應該從您剛才建立的 .NET MAUI 應用程式中刪除這些資料>夾。 這可讓您的 .NET MAUI 應用程式從包含 .NET MAUI UI 的專案取用資源。
在您的 .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(); } }
在您的 .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>
在 .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。
如需此方法的範例,請參閱 範例應用程式。