Incorporamento nativo
In genere, un'app .NET Multipiattaforma App UI (.NET MAUI) include pagine che contengono layout, ad esempio Grid, e che contengono visualizzazioni, ad esempio Button. Le pagine, i layout e le visualizzazioni derivano tutti da Element. L'incorporamento nativo consente l'uso di tutti i controlli MAUI .NET che derivano da Element da per usare in .NET per Android, .NET per iOS, .NET per Mac Catalyst e app native WinUI.
Il processo per l'utilizzo di un controllo MAUI .NET in un'app nativa è il seguente:
- Creare metodi di estensione per eseguire il bootstrap dell'app incorporata nativa. Per altre informazioni, vedere Creare metodi di estensione.
- Creare un singolo progetto MAUI .NET che contiene l'interfaccia utente MAUI .NET e tutte le dipendenze. Per altre informazioni, vedere Creare un singolo progetto MAUI .NET.
- Creare un'app nativa e abilitare il supporto di .NET MAUI. Per altre informazioni, vedere Abilitare il supporto MAUI di .NET.
- Inizializzare .NET MAUI nel progetto di app nativa. Per altre informazioni, vedere Inizializzare .NET MAUI.
- Creare l'interfaccia utente MAUI .NET e convertirla nel tipo nativo appropriato con il
ToPlatformEmbedding
metodo di estensione. Per altre informazioni, vedere Utilizzare controlli MAUI .NET.
- Creare un singolo progetto MAUI .NET che contiene l'interfaccia utente MAUI .NET e tutte le dipendenze. Per altre informazioni, vedere Creare un singolo progetto MAUI .NET.
- Creare un'app nativa e abilitare il supporto di .NET MAUI. Per altre informazioni, vedere Abilitare il supporto MAUI di .NET.
- Inizializzare .NET MAUI nel progetto di app nativa. Per altre informazioni, vedere Inizializzare .NET MAUI.
- Creare l'interfaccia utente MAUI .NET e convertirla nel tipo nativo appropriato con il
ToPlatformEmbedding
metodo di estensione. Per altre informazioni, vedere Utilizzare controlli MAUI .NET.
Nota
Quando si usa l'incorporamento nativo, il motore di data binding di .NET MAUI funziona ancora. Tuttavia, lo spostamento tra le pagine deve essere eseguito usando l'API di spostamento nativa.
Creare metodi di estensione
Prima di creare un'app nativa che utilizza controlli MAUI .NET, è necessario creare un progetto di libreria di classi MAUI .NET ed eliminare la cartella Platforms e la Class1
classe da essa. Aggiungere quindi una classe denominata EmbeddedExtensions
che contiene il codice seguente:
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>();
}
}
Questi metodi di estensione si trovano nello spazio dei Microsoft.Maui.Controls
nomi e vengono usati per eseguire il bootstrap dell'app incorporata nativa in ogni piattaforma. I metodi di estensione fanno riferimento EmbeddedPlatformApplication
ai tipi , EmbeddedWindowHandler
e EmbeddedWindowProvider
che è necessario aggiungere anche al progetto di libreria MAUI .NET.
Il codice seguente illustra la EmbeddedPlatformApplication
classe , che deve essere aggiunta allo stesso progetto di libreria MAUI .NET della EmbeddedExtensions
classe :
#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);
}
}
Il codice seguente illustra la EmbeddedWindowHandler
classe , che deve essere aggiunta allo stesso progetto di libreria MAUI .NET della EmbeddedExtensions
classe :
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.");
}
Il codice seguente illustra la EmbeddedWindowProvider
classe , che deve essere aggiunta allo stesso progetto di libreria MAUI .NET della EmbeddedExtensions
classe :
#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;
}
Creare un singolo progetto MAUI .NET
Prima di creare un'app nativa che utilizza controlli MAUI .NET, è necessario aggiungere un progetto di app MAUI .NET alla stessa soluzione del progetto di libreria di classi MAUI .NET creato in precedenza. Il progetto di app .NET MAUI archivierà l'interfaccia utente che intendi riutilizzare nell'app incorporata nativa. Dopo aver aggiunto un nuovo progetto di app MAUI .NET alla soluzione, seguire questa procedura:
Eliminare la cartella Proprietà dal progetto.
Eliminare la cartella Platforms dal progetto.
Eliminare la cartella Resources/AppIcon dal progetto.
Eliminare la cartella Resources/raw dal progetto.
Eliminare la cartella Resources/Splash dal progetto.
Eliminare la
AppShell
classe dal progetto.Assicurarsi che la
App
classe non imposti laMainPage
proprietà o sostituisci ilCreateWindow
metodo:public partial class App : Application { public App() { InitializeComponent(); } }
Eliminare la
MainPage
classe dal progetto.Modificare il file di progetto in modo che la
$(TargetFramework)
proprietà di compilazione sia impostata sunet8.0
e che la$(OutputType)
proprietà di compilazione venga rimossa:<PropertyGroup> <TargetFramework>net8.0</TargetFramework> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
Importante
Assicurarsi di impostare la proprietà di
$(TargetFramework)
compilazione, non la proprietà di$(TargetFrameworks)
compilazione.Modificare il
CreateMauiApp
metodo nellaMauiProgram
classe in modo che accetti un argomento facoltativo richiamatoAction<MauiAppBuilder>
prima che il metodo restituisca: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(); }
A questo punto è necessario aggiungere l'interfaccia utente MAUI .NET necessaria al progetto, incluse eventuali dipendenze e risorse, e assicurarsi che il progetto venga compilato correttamente.
Creare un singolo progetto MAUI .NET
Prima di creare un'app nativa che utilizza controlli MAUI .NET, è necessario aggiungere un progetto di app MAUI .NET alla stessa soluzione del progetto di libreria di classi MAUI .NET creato in precedenza. Il progetto di app .NET MAUI archivierà l'interfaccia utente che intendi riutilizzare nell'app incorporata nativa. Dopo aver aggiunto un nuovo progetto di app MAUI .NET alla soluzione, seguire questa procedura:
Eliminare la cartella Proprietà dal progetto.
Eliminare la cartella Platforms dal progetto.
Eliminare la cartella Resources/AppIcon dal progetto.
Eliminare la cartella Resources/raw dal progetto.
Eliminare la cartella Resources/Splash dal progetto.
Eliminare la
AppShell
classe dal progetto.Assicurarsi che la
App
classe non imposti laMainPage
proprietà o sostituisci ilCreateWindow
metodo:public partial class App : Application { public App() { InitializeComponent(); } }
Eliminare la
MainPage
classe dal progetto.Modificare il file di progetto in modo che la
$(TargetFramework)
proprietà di compilazione sia impostata sunet9.0
e che la$(OutputType)
proprietà di compilazione venga rimossa:<PropertyGroup> <TargetFramework>net9.0</TargetFramework> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
Importante
Assicurarsi di impostare la proprietà di
$(TargetFramework)
compilazione, non la proprietà di$(TargetFrameworks)
compilazione.MauiProgram
Nella classe modificare ilCreateMauiApp
metodo per accettare unTApp
argomento generico e accettare un argomento facoltativo richiamatoAction<MauiAppBuilder>
prima della restituzione del metodo. Modificare inoltre la chiamata daUseMauiApp<App>
aUseMauiEmbeddedApp<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
Nella classe aggiungere un overload che accetta unCreateMauiApp
argomento facoltativoAction<MauiAppBuilder>
:public static class MauiProgram { ... // Create a MauiApp using the default application. public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) => CreateMauiApp<App>(additional); }
È quindi necessario aggiungere l'interfaccia utente MAUI .NET necessaria al progetto, incluse eventuali dipendenze e risorse, e assicurarsi che il progetto venga compilato correttamente.
Abilitare il supporto DI MAUI per .NET
Per utilizzare i controlli MAUI .NET che derivano da Element in un'app .NET per Android, .NET per iOS, .NET per Mac Catalyst o WinUI, è necessario aggiungere il progetto di app nativa alla stessa soluzione del progetto di libreria di classi .NET MAUI creato in precedenza. È quindi necessario abilitare il supporto MAUI .NET nel file di progetto dell'app nativa impostando le $(UseMaui)
proprietà di compilazione e $(MauiEnablePlatformUsings)
su true
nel primo <PropertyGroup>
nodo del file di progetto:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Per le app .NET per Mac Catalyst, è anche necessario impostare la $(SupportedOSPlatformVersion)
proprietà di compilazione su almeno 14.0:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Per le app .NET per Mac Catalyst, è anche necessario impostare la $(SupportedOSPlatformVersion)
proprietà di compilazione su almeno 15.0:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Per le app WinUI, dovrai anche impostare la proprietà di $(EnableDefaultXamlItems)
compilazione su false
:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
<EnableDefaultXamlItems>false</EnableDefaultXamlItems>
</PropertyGroup>
In questo modo si interrompe la ricezione di errori di compilazione relativi al InitializeComponent
metodo già definito.
Aggiungere quindi elementi di compilazione $(PackageReference)
al file di progetto per i Microsoft.Maui.Controls
pacchetti NuGet e Microsoft.Maui.Controls.Compatiblity
:
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>
Aggiungere quindi elementi di compilazione $(PackageReference)
al file di progetto per il Microsoft.Maui.Controls
pacchetto NuGet:
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
</ItemGroup>
Inizializzare .NET MAUI
.NET MAUI deve essere inizializzato prima che un progetto di app nativa possa costruire un controllo MAUI .NET. La scelta di quando inizializzarla dipende principalmente da quando è più conveniente nel flusso dell'app. È possibile eseguirla all'avvio o subito prima che venga costruito un controllo MAUI .NET. L'approccio descritto di seguito consiste nell'inizializzare .NET MAUI quando viene creata l'interfaccia utente iniziale dell'app.
In genere, il modello per l'inizializzazione di .NET MAUI in un progetto di app nativa è il seguente:
- Creare un oggetto MauiApp.
- Creare un MauiContext oggetto dall'oggetto MauiApp . L'oggetto MauiContext verrà usato per ottenere una visualizzazione nativa dalla vista MAUI .NET.
In Android, l'override OnCreate
nella MainActivity
classe è in genere la posizione in cui eseguire attività correlate all'avvio dell'app. L'esempio di codice seguente mostra l'inizializzazione di .NET MAUI nella MainActivity
classe :
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
...
}
}
In iOS e Mac Catalyst, la AppDelegate
classe deve essere modificata in modo da restituire true
per l'override 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;
}
Il WillConnect
metodo nella SceneDelegate
classe deve quindi essere modificato per creare il controller di visualizzazione principale e impostarlo come visualizzazione di 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();
}
...
}
Quindi, nell'editor XML aprire il file Info.plist e aggiungere il codice XML seguente alla fine del file:
<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>
.NET MAUI può quindi essere inizializzato nel ViewDidLoad
metodo nel controller di visualizzazione principale:
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
...
}
}
In Windows la MainWindow
classe è in genere la posizione in cui eseguire attività di avvio dell'app correlate all'interfaccia utente:
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
...
}
}
In questo esempio l'oggetto viene creato usando l'inizializzazione MauiApp differita. Il UseMauiEmbedding
metodo di estensione viene richiamato sull'oggetto MauiAppBuilder . Di conseguenza, il progetto di app nativa deve includere un riferimento al progetto di libreria di classi MAUI .NET creato che contiene questo metodo di estensione. Viene MauiContext quindi creato un oggetto dall'oggetto MauiApp , con un oggetto bool
che determina la posizione di ambito del contesto. L'oggetto MauiContext verrà usato durante la conversione dei controlli MAUI .NET in tipi nativi.
L'incorporamento può essere eseguito in un contesto dell'app o in un contesto di finestra, ma per la massima compatibilità MAUI .NET deve essere eseguito in un contesto di finestra.
Contesto dell'app
L'incorporamento nativo può essere eseguito in un contesto dell'app, in cui l'app nativa non ha alcuna conoscenza di una finestra. Con questo approccio, l'inizializzazione dell'incorporamento nativo richiede di:
- Creare un oggetto MauiApp.
- Creare un MauiContext oggetto dall'oggetto MauiApp . L'oggetto MauiContext verrà usato per ottenere una visualizzazione nativa dalla vista MAUI .NET.
L'esempio seguente illustra questo approccio:
var mauiApp = MauiProgram.CreateMauiApp();
var context = new MauiContext(mauiApp.Services); // Activity also needs passing on Android
Una vista MAUI .NET può quindi essere creata e convertita in una visualizzazione nativa con il ToPlatformEmbedded
metodo di estensione, che richiede l'oggetto MauiContext come argomento.
Questo approccio è adatto per scenari in cui un'app nativa deve incorporare una semplice interfaccia utente MAUI di .NET, ma non richiede l'accesso a tutte le funzionalità MAUI di .NET. Lo svantaggio di questo approccio è che gli strumenti come il ricaricamento rapido e alcune funzionalità MAUI di .NET non funzioneranno.
Suggerimento
La creazione di un MauiApp oggetto ogni volta che una visualizzazione MAUI .NET viene incorporata come visualizzazione nativa non è consigliata. Questo problema può essere problematico se le visualizzazioni incorporate accedono alla Application.Current
proprietà . L'oggetto MauiApp può invece essere creato come istanza statica condivisa:
public static class MyEmbeddedMauiApp
{
static MauiApp? _shared;
public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}
Con questo approccio, è possibile creare un'istanza dell'oggetto MauiApp all'inizio del ciclo di vita dell'app per evitare un piccolo ritardo la prima volta che si incorpora una visualizzazione MAUI .NET nell'app.
In Android un frammento rappresenta una parte dell'interfaccia utente all'interno di un'attività. L'esempio di codice seguente mostra l'inizializzazione di .NET MAUI in un frammento:
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);
...
}
}
In iOS e Mac Catalyst, la AppDelegate
classe deve essere modificata in modo da restituire true
per l'override 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;
}
Il WillConnect
metodo nella SceneDelegate
classe deve quindi essere modificato per creare il controller di visualizzazione principale e impostarlo come visualizzazione di 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();
}
...
}
Quindi, nell'editor XML aprire il file Info.plist e aggiungere il codice XML seguente alla fine del file:
<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>
.NET MAUI può quindi essere inizializzato nel ViewDidLoad
metodo nel controller di visualizzazione principale:
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);
...
}
}
In Windows la MainWindow
classe è in genere la posizione in cui eseguire attività di avvio dell'app correlate all'interfaccia utente:
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);
...
}
}
In questo esempio l'oggetto MauiApp viene creato come istanza statica condivisa. Quando questo oggetto viene creato, MauiProgram.CreateMauiApp
viene chiamato che a sua volta chiama il UseMauiEmbedding
metodo di estensione sull'oggetto MauiAppBuilder . Di conseguenza, il progetto di app nativa deve includere un riferimento al progetto di libreria di classi MAUI .NET creato che contiene la MauiProgram
classe e l'interfaccia utente MAUI .NET. Viene MauiContext quindi creato un oggetto dall'oggetto MauiApp , con ambito all'oggetto MauiApp . L'oggetto MauiContext verrà usato durante la conversione dei controlli MAUI .NET in tipi nativi.
Contesto finestra
L'incorporamento nativo può essere eseguito in un contesto di finestra, in cui l'app nativa ha una conoscenza di una finestra. In alcuni scenari, le viste MAUI .NET richiedono l'accesso a una finestra per funzionare correttamente. Ad esempio, i trigger adattivi richiedono l'accesso alla finestra di una visualizzazione e, se non sono presenti finestre, non funzionano.
Con questo approccio, l'inizializzazione dell'incorporamento nativo richiede di:
- Creare un oggetto MauiApp.
- Creare un MauiContext oggetto con il
CreateEmbeddedWindowContext
metodo . L'oggetto MauiContext verrà usato per ottenere una visualizzazione nativa dalla vista MAUI .NET.
Il CreateEmbeddedWindowContext
metodo crea un contesto di finestra che correla una finestra nativa a una finestra MAUI .NET:
var mauiApp = MauiProgram.CreateMauiApp();
var context = mauiApp.CreateEmbeddedWindowContext(this);
Una vista MAUI .NET può quindi essere creata e convertita in una visualizzazione nativa con il ToPlatformEmbedded
metodo di estensione, che richiede l'oggetto MauiContext come argomento.
Nota
Il ToPlatformEmbedded
metodo di estensione dispone di un overload che aggiunge una visualizzazione MAUI .NET a una finestra incorporata.
Il vantaggio di questo approccio è che è disponibile una singola finestra MAUI .NET per ogni finestra nativa, le API correlate alla finestra funzioneranno correttamente e gli strumenti come il ricaricamento rapido funzionano correttamente.
Suggerimento
La creazione di un MauiApp oggetto ogni volta che una visualizzazione MAUI .NET viene incorporata come visualizzazione nativa non è consigliata. Questo problema può essere problematico se le visualizzazioni incorporate accedono alla Application.Current
proprietà . L'oggetto MauiApp può invece essere creato come istanza statica condivisa:
public static class MyEmbeddedMauiApp
{
static MauiApp? _shared;
public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}
Con questo approccio, è possibile creare un'istanza dell'oggetto MauiApp all'inizio del ciclo di vita dell'app per evitare un piccolo ritardo la prima volta che si incorpora una visualizzazione MAUI .NET nell'app.
In Android un frammento rappresenta una parte dell'interfaccia utente all'interno di un'attività. L'esempio di codice seguente mostra l'inizializzazione di .NET MAUI in un frammento:
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;
...
}
}
In iOS e Mac Catalyst, la AppDelegate
classe deve essere modificata in modo da restituire true
per l'override 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;
}
Il WillConnect
metodo nella SceneDelegate
classe deve quindi essere modificato per creare il controller di visualizzazione principale e impostarlo come visualizzazione di 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();
}
...
}
Quindi, nell'editor XML aprire il file Info.plist e aggiungere il codice XML seguente alla fine del file:
<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>
.NET MAUI può quindi essere inizializzato nel ViewDidLoad
metodo nel controller di visualizzazione principale:
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;
...
}
}
In Windows la MainWindow
classe è in genere la posizione in cui eseguire attività di avvio dell'app correlate all'interfaccia utente:
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;
...
}
}
In questo esempio l'oggetto MauiApp viene creato come istanza statica condivisa. Quando questo oggetto viene creato, MauiProgram.CreateMauiApp
viene chiamato che a sua volta chiama il UseMauiEmbedding
metodo di estensione sull'oggetto MauiAppBuilder . Di conseguenza, il progetto di app nativa deve includere un riferimento al progetto di libreria di classi MAUI .NET creato che contiene la MauiProgram
classe e l'interfaccia utente MAUI .NET. Viene MauiContext quindi creato un oggetto con il CreateEmbeddedWindowContext
metodo , che ha come ambito la finestra. L'oggetto MauiContext verrà usato durante la conversione dei controlli MAUI .NET in tipi nativi.
Utilizzare controlli MAUI .NET
Dopo l'inizializzazione di .NET MAUI nell'app nativa, è possibile aggiungere l'interfaccia utente MAUI .NET al layout dell'app nativa. A tale scopo, è possibile creare un'istanza dell'interfaccia utente e convertirla nel tipo nativo appropriato con il ToPlatformEmbedded
metodo di estensione.
In Android, il ToPlatformEmbedded
metodo di estensione converte il controllo MAUI .NET in un oggetto Android View :
var mauiView = new MyMauiContent();
Android.Views.View nativeView = mauiView.ToPlatformEmbedded(context);
In questo esempio un ContentViewoggetto derivato da viene convertito in un oggetto Android View .
Nota
Il ToPlatformEmbedded
metodo di estensione si trova nella libreria di classi MAUI .NET creata in precedenza. Di conseguenza, il progetto di app nativa deve includere un riferimento a tale progetto.
Nota
Il ToPlatformEmbedded
metodo di estensione si trova nello spazio dei Microsoft.Maui.Controls.Embedding nomi . Di conseguenza, il progetto di app nativa deve includere un'istruzione using
per tale spazio dei nomi.
L'oggetto View può quindi essere aggiunto a un layout nell'app nativa:
rootLayout.AddView(nativeView, new LinearLayout.LayoutParams(MatchParent, WrapContent));
In iOS e Mac Catalyst il ToPlatformEmbedded
metodo di estensione converte il controllo MAUI .NET in un UIView oggetto :
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);
nativeView.WidthAnchor.ConstraintEqualTo(View.Frame.Width).Active = true;
nativeView.HeightAnchor.ConstraintEqualTo(500).Active = true;
In questo esempio un ContentViewoggetto derivato da viene convertito in un UIView oggetto e quindi vengono impostati vincoli di larghezza e altezza per consentire l'interazione.
Nota
Il ToPlatformEmbedded
metodo di estensione si trova nella libreria di classi MAUI .NET creata in precedenza. Di conseguenza, il progetto di app nativa deve includere un riferimento a tale progetto.
L'oggetto UIView può quindi essere aggiunto a una visualizzazione nel controller di visualizzazione:
stackView.AddArrangedSubView(nativeView);
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);
In questo esempio un ContentViewoggetto derivato da viene convertito in un UIView oggetto .
Nota
Il ToPlatformEmbedded
metodo di estensione si trova nello spazio dei Microsoft.Maui.Controls.Embedding nomi . Di conseguenza, il progetto di app nativa deve includere un'istruzione using
per tale spazio dei nomi.
L'oggetto UIView può quindi essere aggiunto a una visualizzazione nel controller di visualizzazione:
stackView.AddArrangedSubView(new ContainerView(nativeView));
ContainerView
è un tipo personalizzato che esegue il wrapping della visualizzazione MAUI .NET per assicurarsi che venga ridimensionato correttamente. A tale scopo, si esegue il reindirizzamento IntrinsicContentSize
alla vista MAUI di SizeThatFits
.NET:
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();
}
}
È anche possibile usare un ToUIViewController
metodo di estensione in .NET MAUI per convertire una pagina MAUI .NET in :UIViewController
MyMauiPage myMauiPage = new MyMauiPage();
UIViewController myPageController = myMauiPage.ToUIViewController(context);
In questo esempio un ContentPageoggetto derivato da viene convertito in un oggetto UIViewController.
In Windows il ToPlatformEmbedded
metodo di estensione converte il controllo MAUI .NET in un FrameworkElement oggetto :
var mauiView = new MyMauiContent();
FrameworkElement nativeView = myMauiPage.ToPlatformEmbedded(context);
In questo esempio un ContentViewoggetto derivato da viene convertito in un FrameworkElement oggetto . L'oggetto FrameworkElement può quindi essere impostato come contenuto di una pagina WinUI.
Nota
Il ToPlatformEmbedded
metodo di estensione si trova nella libreria di classi MAUI .NET creata in precedenza. Di conseguenza, il progetto di app nativa deve includere un riferimento a tale progetto.
Nota
Il ToPlatformEmbedded
metodo di estensione si trova nello spazio dei Microsoft.Maui.Controls.Embedding nomi . Di conseguenza, il progetto di app nativa deve includere un'istruzione using
per tale spazio dei nomi.
L'oggetto FrameworkElement può quindi essere aggiunto a un layout nell'app nativa:
stackPanel.Children.Add(nativeView);
Importante
Per evitare un errore, il ricaricamento rapido XAML deve essere disabilitato prima di eseguire un'app incorporata nativa nella configurazione di debug.
Supporto del ricaricamento rapido XAML
Il ricaricamento rapido XAML non è supportato nelle app incorporate native. Tuttavia, puoi comunque usare il ricaricamento rapido XAML per scorrere rapidamente l'interfaccia utente MAUI di .NET creando un'app MAUI .NET che usa l'interfaccia utente MAUI .NET.
Per visualizzare l'interfaccia utente MAUI .NET con ricaricamento rapido XAML:
Nel progetto contenente l'interfaccia utente MAUI .NET aggiornare la
MauiProgram
classe per aggiungere unCreateMauiApp
overload e modificare il metodo esistenteCreateMauiApp
per accettare un argomento generico: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(); } }
Nel progetto contenente l'interfaccia utente MAUI .NET convertire ogni dizionario risorse da un file XAML autonomo in un dizionario risorse supportato da un file code-behind.
Nel progetto contenente l'interfaccia utente MAUI di .NET aggiornare l'istanza del dizionario risorse, in genere in App.xaml, in modo che la
Source
proprietà specifichi anche l'assembly che contiene il dizionario risorse:<ResourceDictionary Source="Resources/Styles/Colors.xaml;assembly=NativeEmbeddingDemo" /> <ResourceDictionary Source="Resources/Styles/Styles.xaml;assembly=NativeEmbeddingDemo" />
Creare una nuova app MAUI .NET e aggiungerla alla soluzione contenente il progetto di interfaccia utente MAUI .NET e le app incorporate native.
Nel progetto di app .NET MAUI aggiungere un riferimento al progetto che contiene l'interfaccia utente MAUI .NET.
Nel progetto di app .NET MAUI eliminare tutte le cartelle figlio della risorsa in cui la risorsa viene fornita dal progetto di interfaccia utente MAUI .NET. Ad esempio, se il progetto dell'interfaccia utente MAUI .NET contiene le cartelle Tipi di carattere risorse>, > Immagini risorse e Stili risorse>, queste cartelle devono essere eliminate dall'app MAUI .NET appena creata. In questo modo l'app MAUI .NET può usare le risorse del progetto contenente l'interfaccia utente MAUI di .NET.
Nell'app .NET MAUI aggiornare la
App
classe in modo che derivi dallaApp
classe nel progetto di interfaccia utente MAUI .NET:<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>
Aggiornare quindi il file code-behind per la
App
classe in modo che derivi dallaApp
classe nel progetto dell'interfaccia utente MAUI .NET e carichi tutte le risorse XAML da questo progetto:public partial class TestApp : myMauiUIProject.App { public TestApp() { var baseResources = Resources; InitializeComponent(); Resources.MergedDictionaries.Add(baseResources); MainPage = new HostPage(); } }
Nell'app .NET MAUI aggiungere una pagina che visualizza l'interfaccia utente dal progetto contenente l'interfaccia utente MAUI .NET:
<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>
Nell'app .NET MAUI aggiornare la
MauiProgram
classe per chiamare il metodo nel progetto contenente l'interfacciaCreateMauiApp
utente MAUI di .NET:public static class MauiProgram { public static MauiApp CreateMauiApp() => NativeEmbeddingDemo.MauiProgram.CreateMauiApp<TestApp>(builder => { // Add any test harness configuration such as service stubs or mocks. }); }
A questo ora dovrebbe essere possibile eseguire il progetto di app .NET MAUI in ogni piattaforma e usare il ricaricamento rapido XAML per scorrere l'interfaccia utente MAUI di .NET.