Nativní vkládání

Projděte si ukázku. Procházení ukázky

Aplikace .NET Pro víceplatformní aplikace (.NET MAUI) obvykle obsahuje stránky obsahující rozložení, například Grida rozložení, která obsahují zobrazení, například Button. Stránky, rozložení a zobrazení jsou odvozeny od Element. Nativní vkládání umožňuje všechny ovládací prvky .NET MAUI odvozené od Element použití v .NET pro Android, .NET pro iOS, .NET pro Mac Catalyst a nativní aplikace WinUI.

Proces využívání ovládacího prvku .NET MAUI v nativní aplikaci je následující:

  1. Vytvořte metody rozšíření pro spuštění nativní vložené aplikace. Další informace naleznete v tématu Vytvoření rozšiřujících metod.
  2. Vytvořte jeden projekt .NET MAUI, který obsahuje uživatelské rozhraní .NET MAUI a všechny závislosti. Další informace najdete v tématu Vytvoření jednoho projektu .NET MAUI.
  3. Vytvořte nativní aplikaci a povolte v ní podporu .NET MAUI. Další informace najdete v tématu Povolení podpory .NET MAUI.
  4. Inicializace rozhraní .NET MAUI voláním UseMauiEmbedding metody rozšíření. Další informace najdete v tématu Inicializace rozhraní .NET MAUI.
  5. Vytvořte uživatelské rozhraní .NET MAUI a pomocí metody rozšíření ho ToPlatformEmbedding převeďte na příslušný nativní typ. Další informace najdete v tématu Využití ovládacích prvků .NET MAUI.

Poznámka:

Při použití nativního vkládání stále funguje modul datových vazeb .NET MAUI. Navigace na stránce se ale musí provádět pomocí nativního navigačního rozhraní API.

Vytvoření rozšiřujících metod

Před vytvořením nativní aplikace, která využívá ovládací prvky .NET MAUI, byste nejprve měli vytvořit projekt knihovny tříd .NET MAUI a odstranit složku Platformy a Class1 třídu z ní. Pak do ní EmbeddedExtensions přidejte třídu, která obsahuje následující kód:

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

Tyto metody rozšíření jsou v Microsoft.Maui.Controls oboru názvů a používají se ke spuštění nativní vložené aplikace na každé platformě. Metody rozšíření odkazují EmbeddedPlatformApplicationna , EmbeddedWindowHandlera EmbeddedWindowProvider typy, které musíte také přidat do projektu knihovny .NET MAUI.

Následující kód ukazuje EmbeddedPlatformApplication třídu, která by se měla přidat do stejného projektu knihovny .NET MAUI jako EmbeddedExtensions třída:

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

Následující kód ukazuje EmbeddedWindowHandler třídu, která by se měla přidat do stejného projektu knihovny .NET MAUI jako EmbeddedExtensions třída:

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

Následující kód ukazuje EmbeddedWindowProvider třídu, která by se měla přidat do stejného projektu knihovny .NET MAUI jako EmbeddedExtensions třída:

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

Vytvoření jednoho projektu .NET MAUI

Před vytvořením nativní aplikace, která využívá ovládací prvky .NET MAUI, byste měli přidat projekt aplikace .NET MAUI do stejného řešení jako projekt knihovny tříd .NET MAUI, který jste vytvořili dříve. Projekt aplikace .NET MAUI uloží uživatelské rozhraní, které chcete znovu použít v nativní vložené aplikaci. Po přidání nového projektu aplikace .NET MAUI do řešení proveďte následující kroky:

  1. Odstraňte složku Vlastnosti z projektu.

  2. Odstraňte složku Platformy z projektu.

  3. Odstraňte složku Resources/AppIcon z projektu.

  4. Odstraňte složku Resources/raw z projektu.

  5. Odstraňte složku Resources/Splash z projektu.

  6. Odstraňte třídu AppShell z projektu.

  7. App Upravte třídu tak, aby nenastavil MainPage vlastnost:

    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
        }
    }
    
  8. Odstraňte třídu MainPage z projektu.

  9. Upravte soubor projektu tak, aby $(TargetFrameworks) byla vlastnost sestavení nastavena na net8.0hodnotu a $(OutputType) vlastnost sestavení se odebere:

    <PropertyGroup>
      <TargetFrameworks>net8.0</TargetFrameworks>
    
      <RootNamespace>MyMauiApp</RootNamespace>
      <UseMaui>true</UseMaui>
      <SingleProject>true</SingleProject>
      <ImplicitUsings>enable</ImplicitUsings>
      <Nullable>enable</Nullable>
    
      ...
    </PropertyGroup>
    
  10. Upravte metodu CreateMauiAppMauiProgram ve třídě tak, aby přijímá volitelný Action<MauiAppBuilder> argument vyvolaný před vrácením metody:

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

V tomto okamžiku byste měli do projektu přidat požadované uživatelské rozhraní .NET MAUI, včetně všech závislostí a prostředků, a zajistit správné sestavení projektu.

Povolení podpory rozhraní .NET MAUI

Pokud chcete využívat ovládací prvky .NET MAUI odvozené z Element aplikace .NET pro Android, .NET pro iOS, .NET for Mac Catalyst nebo WinUI, měli byste svůj nativní projekt aplikace přidat do stejného řešení jako projekt knihovny tříd .NET MAUI, který jste vytvořili dříve. Potom byste měli povolit podporu .NET MAUI v souboru projektu vaší nativní aplikace nastavením $(UseMaui) vlastností sestavení $(MauiEnablePlatformUsings) na true první <PropertyGroup> uzel v souboru projektu:

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

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

Pro aplikace .NET for Mac Catalyst budete také muset nastavit $(SupportedOSPlatformVersion) vlastnost sestavení na minimálně 14.0:

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

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

U aplikací WinUI budete také muset nastavit $(EnableDefaultXamlItems) vlastnost sestavení na false:

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

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

Tím přestanete dostávat chyby sestavení týkající se InitializeComponent již definované metody.

Potom přidejte $(PackageReference) položky sestavení do souboru projektu pro Microsoft.Maui.Controls balíčky NuGet:Microsoft.Maui.Controls.Compatiblity

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

Inicializace rozhraní .NET MAUI

Před vytvořením ovládacího prvku .NET MAUI je nutné inicializovat nativní projekt aplikace. Volba, kdy se má inicializovat, závisí především na tom, kdy je to v toku aplikace nejvhodnější – dá se provést při spuštění nebo těsně před vytvořením ovládacího prvku .NET MAUI. Zde uvedený přístup spočívá v inicializaci rozhraní .NET MAUI při vytvoření počátečního uživatelského rozhraní aplikace.

Vzor pro inicializaci .NET MAUI v nativním projektu aplikace je obvykle následující:

V Androidu OnCreateMainActivity je přepsání třídy obvykle místem pro provádění úloh souvisejících se spuštěním aplikace. Následující příklad kódu ukazuje inicializaci .NET MAUI ve MainActivity třídě:

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

            ...              
        }
    }
}

V systému iOS a Mac Catalyst by se přepsání ve AppDelegate třídě mělo upravit tak, FinishedLaunching aby se vytvořil hlavní kontroler zobrazení:

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

Rozhraní .NET MAUI je pak možné inicializovat v ViewDidLoad metodě v hlavním kontroleru zobrazení:

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

            ...
        }
    }
}

Ve MainWindow Windows je třída obvykle místem pro provádění úloh spuštění aplikace souvisejících s uživatelským rozhraním:

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

            ...
        }
    }
}

V tomto příkladu MauiApp se objekt vytvoří pomocí opožděné inicializace. Rozšiřující UseMauiEmbedding metoda je vyvolána na objektu MauiAppBuilder . Proto by váš nativní projekt aplikace měl obsahovat odkaz na projekt knihovny tříd .NET MAUI, který jste vytvořili, který obsahuje tuto metodu rozšíření. Objekt MauiContext se pak vytvoří z objektu MauiApp s určením bool , odkud je kontext vymezen. Objekt MauiContext se použije při převodu ovládacích prvků .NET MAUI na nativní typy.

Využívání ovládacích prvků .NET MAUI

Po inicializaci rozhraní .NET MAUI v nativní aplikaci můžete do rozložení nativní aplikace přidat uživatelské rozhraní .NET MAUI. Toho lze dosáhnout vytvořením instance uživatelského rozhraní a jeho převodem na příslušný nativní typ pomocí ToPlatformEmbedded rozšiřující metody.

V Androidu ToPlatformEmbedded metoda rozšíření převede ovládací prvek .NET MAUI na objekt Androidu View :

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

V tomto příkladu je odvozený ContentViewobjekt převeden na objekt Androidu View .

Poznámka:

Metoda ToPlatformEmbedded rozšíření je v knihovně tříd .NET MAUI, kterou jste vytvořili dříve. Proto by váš nativní projekt aplikace měl obsahovat odkaz na tento projekt.

Objekt View pak můžete přidat do rozložení v nativní aplikaci:

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

V systému iOS a Mac Catalyst ToPlatformEmbedded metoda rozšíření převede ovládací prvek .NET MAUI na 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;

V tomto příkladu se odvozený ContentViewobjekt převede na UIView objekt a pak jsou na něm nastavena omezení šířky a výšky, aby umožňovala interakci.

Poznámka:

Metoda ToPlatformEmbedded rozšíření je v knihovně tříd .NET MAUI, kterou jste vytvořili dříve. Proto by váš nativní projekt aplikace měl obsahovat odkaz na tento projekt.

Objekt UIView pak můžete přidat do zobrazení v kontroleru zobrazení:

stackView.AddArrangedSubView(nativeView);

Kromě toho lze metodu ToUIViewController rozšíření v .NET MAUI použít k pokusu o převod stránky .NET MAUI na UIViewController:

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

V tomto příkladu ContentPageje odvozený objekt převeden na .UIViewController

Ve Windows ToPlatformEmbedded metoda rozšíření převede ovládací prvek .NET MAUI na FrameworkElement objekt:

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

V tomto příkladu je odvozený ContentViewobjekt převeden na FrameworkElement objekt. Objekt FrameworkElement lze pak nastavit jako obsah stránky WinUI.

Objekt FrameworkElement pak můžete přidat do rozložení v nativní aplikaci:

stackPanel.Children.Add(nativeView);

Důležité

Aby nedocházelo k chybě, mělo by být opětovné načítání XAML za provozu zakázané před spuštěním nativní vložené aplikace v konfiguraci ladění.