Встроенное внедрение
Как правило, приложение многоплатформенного пользовательского интерфейса приложений .NET (.NET MAUI) включает страницы, содержащие макеты, например макеты и макеты, содержащие представления, напримерGridButton. Страницы, макеты и представления являются производными от Element. Встроенное внедрение позволяет использовать любые элементы управления MAUI .NET, производные от Element использования в .NET для Android, .NET для iOS, .NET для Mac Catalyst и собственных приложений WinUI.
Процесс использования элемента управления MAUI .NET в собственном приложении выглядит следующим образом:
- Создайте методы расширения для загрузки собственного внедренного приложения. Дополнительные сведения см. в разделе "Создание методов расширения".
- Создайте единый проект .NET MAUI, содержащий пользовательский интерфейс .NET MAUI и все зависимости. Дополнительные сведения см. в статье "Создание единого проекта .NET MAUI".
- Создайте собственное приложение и включите в ней поддержку .NET MAUI. Дополнительные сведения см. в разделе "Включение поддержки MAUI для .NET".
- Инициализация .NET MAUI путем
UseMauiEmbedding
вызова метода расширения. Дополнительные сведения см. в разделе Инициализация MAUI .NET. - Создайте пользовательский интерфейс .NET MAUI и преобразуйте его в соответствующий
ToPlatformEmbedding
собственный тип с помощью метода расширения. Дополнительные сведения см. в разделе "Использование элементов управления MAUI .NET".
Примечание.
При использовании встроенного внедрения подсистема привязки данных .NET MAUI по-прежнему работает. Однако навигация по страницам должна выполняться с помощью собственного API навигации.
Создание методов расширения
Перед созданием собственного приложения, использующее элементы управления MAUI .NET, необходимо сначала создать проект библиотеки классов .NET MAUI и удалить папку Platform и 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
класс, который следует добавить в тот же проект библиотеки .NET MAUI, что и EmbeddedExtensions
класс:
#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
класс, который следует добавить в тот же проект библиотеки .NET MAUI, что и EmbeddedExtensions
класс:
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
класс, который следует добавить в тот же проект библиотеки .NET MAUI, что и EmbeddedExtensions
класс:
#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
Перед созданием собственного приложения, использующее элементы управления MAUI .NET, необходимо добавить проект приложения .NET MAUI в то же решение, что и проект библиотеки классов .NET MAUI, созданный ранее. Проект приложения .NET MAUI будет хранить пользовательский интерфейс, который вы планируете повторно использовать в собственном внедренном приложении. После добавления нового проекта приложения MAUI .NET в решение выполните следующие действия:
Удалите папку "Свойства" из проекта.
Удалите папку Platform из проекта.
Удалите папку Resources/AppIcon из проекта.
Удалите папку Resources/raw из проекта.
Удалите папку Resources/Splash из проекта.
AppShell
Удалите класс из проекта.Измените
App
класс таким образом, чтобы он не задалMainPage
свойство:public partial class App : Application { public App() { InitializeComponent(); } }
MainPage
Удалите класс из проекта.Измените файл проекта таким образом, чтобы
$(TargetFrameworks)
свойство сборки было заданоnet8.0
, и$(OutputType)
свойство сборки удаляется:<PropertyGroup> <TargetFrameworks>net8.0</TargetFrameworks> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
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, включая все зависимости и ресурсы, и убедиться, что проект будет правильно построен.
Включение поддержки .NET MAUI
Чтобы использовать элементы управления .NET MAUI, производные от Element .NET для Android, .NET для iOS, .NET для Mac Catalyst или приложения WinUI, необходимо добавить собственный проект приложения в то же решение, что и проект библиотеки классов .NET MAUI, созданный ранее. Затем необходимо включить поддержку .NET MAUI в файле проекта собственного приложения, задав $(UseMaui)
свойства true
сборки $(MauiEnablePlatformUsings)
в первом <PropertyGroup>
узле в файле проекта:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Для приложений .NET для Mac Catalyst также необходимо задать $(SupportedOSPlatformVersion)
для свойства сборки не менее 14.0:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Для приложений WinUI также необходимо задать для свойства false
сборки $(EnableDefaultXamlItems)
значение :
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
<EnableDefaultXamlItems>false</EnableDefaultXamlItems>
</PropertyGroup>
Это приведет к остановке получения ошибок сборки о том, что InitializeComponent
метод уже определен.
Затем добавьте $(PackageReference)
элементы сборки Microsoft.Maui.Controls
в файл проекта для пакетов NuGet:Microsoft.Maui.Controls.Compatiblity
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>
Инициализация .NET MAUI
.NET MAUI необходимо инициализировать, прежде чем проект собственного приложения может создать элемент управления .NET MAUI. Выбор времени инициализации в первую очередь зависит от того, когда он наиболее удобно в потоке приложений, он может выполняться при запуске или непосредственно перед созданием элемента управления MAUI .NET. Описанный здесь подход заключается в инициализации .NET MAUI при создании начального пользовательского интерфейса приложения.
Как правило, шаблон инициализации .NET MAUI в проекте собственного приложения выглядит следующим образом:
- Создание объекта MauiApp.
- MauiContext Создайте объект из MauiApp объекта.
В Android OnCreate
переопределение в MainActivity
классе обычно является местом для выполнения связанных с приложением задач запуска приложений. В следующем примере кода показано, как инициализировать MAUI .NET в MainActivity
классе:
namespace MyNativeEmbeddedApp.Droid
{
[Activity(Label = "@string/app_name", MainLauncher = true, Theme = "@style/AppTheme")]
public class MainActivity : Activity
{
public static readonly Lazy<MauiApp> MauiApp = new(() =>
{
var mauiApp = MauiProgram.CreateMauiApp(builder =>
{
builder.UseMauiEmbedding();
});
return mauiApp;
});
public static bool UseWindowContext = true;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MainActivity.MauiApp.Value;
// Create .NET MAUI context
var mauiContext = UseWindowContext
? mauiApp.CreateEmbeddedWindowContext(this) // Create window context
: new MauiContext(mauiApp.Services, this); // Create app context
...
}
}
}
В iOS и Mac Catalyst FinishedLaunching
необходимо изменить переопределение в AppDelegate
классе, чтобы создать основной контроллер представления:
namespace MyNativeEmbeddedApp.iOS
{
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var vc = new MainViewController();
Window.RootViewController = vc;
Window.MakeKeyAndVisible();
return true;
}
}
}
Затем .NET MAUI можно инициализировать в методе в контроллере основного ViewDidLoad
представления:
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
...
}
}
}
В MainWindow
Windows класс обычно является местом для выполнения задач запуска приложения, связанных с пользовательским интерфейсом:
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
...
}
}
}
В этом примере MauiApp объект создается с помощью отложенной инициализации. Метод UseMauiEmbedding
расширения вызывается в объекте MauiAppBuilder . Поэтому проект собственного приложения должен содержать ссылку на созданный проект библиотеки классов .NET MAUI, содержащий этот метод расширения. Затем MauiContext объект создается из MauiApp объекта с определением bool
того, откуда область контекст. Объект MauiContext будет использоваться при преобразовании элементов управления MAUI .NET в собственные типы.
Использование элементов управления MAUI .NET
После инициализации .NET MAUI в собственном приложении вы можете добавить пользовательский интерфейс .NET MAUI в макет собственного приложения. Это можно сделать, создав экземпляр пользовательского интерфейса и преобразовав его в соответствующий собственный тип с ToPlatformEmbedded
помощью метода расширения.
В ToPlatformEmbedded
Android метод расширения преобразует элемент управления MAUI .NET в объект Android View :
var mauiView = new MyMauiContent();
Android.Views.View nativeView = mauiView.ToPlatformEmbedded(mauiContext);
В этом примере производный ContentViewобъект преобразуется в объект Android View .
Примечание.
Метод ToPlatformEmbedded
расширения находится в созданной ранее библиотеке классов .NET MAUI. Поэтому проект собственного приложения должен содержать ссылку на этот проект.
Затем View объект можно добавить в макет в собственном приложении:
rootLayout.AddView(nativeView, new LinearLayout.LayoutParams(MatchParent, WrapContent));
В iOS и Mac Catalyst ToPlatformEmbedded
метод расширения преобразует элемент управления MAUI .NET в UIView объект:
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(mauiContext);
В этом примере производный ContentViewобъект преобразуется в UIView объект.
Примечание.
Метод ToPlatformEmbedded
расширения находится в созданной ранее библиотеке классов .NET MAUI. Поэтому проект собственного приложения должен содержать ссылку на этот проект.
Затем UIView объект можно добавить в представление в контроллере представления:
stackView.AddArrangedSubView(nativeView);
Предупреждение
В настоящее время невозможно взаимодействовать с пользовательским интерфейсом .NET MAUI в iOS и Mac Catalyst. Дополнительные сведения см. в статье о проблеме GitHub #19340.
Кроме того, ToUIViewController
метод расширения в .NET MAUI можно использовать для преобразования страницы UIViewControllerMAUI .NET в :
MyMauiPage myMauiPage = new MyMauiPage();
UIViewController myPageController = myMauiPage.ToUIViewController(mauiContext);
В этом примере производный ContentPageобъект преобразуется в объект UIViewController.
В ToPlatformEmbedded
Windows метод расширения преобразует элемент управления MAUI .NET в FrameworkElement
объект:
var mauiView = new MyMauiContent();
FrameworkElement nativeView = myMauiPage.ToPlatformEmbedded(mauiContext);
В этом примере производный ContentViewобъект преобразуется в FrameworkElement
объект. Затем FrameworkElement
объект можно задать как содержимое страницы WinUI.
Затем FrameworkElement
объект можно добавить в макет в собственном приложении:
stackPanel.Children.Add(nativeView);
Внимание
Чтобы избежать ошибки, перед запуском собственного внедренного приложения в конфигурации отладки необходимо отключить горячую перезагрузку XAML.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по