Abhängigkeitsinjektion
.NET MAUI (.NET Multi-Platform App UI) bietet integrierte Unterstützung für die Verwendung der Abhängigkeitsinjektion. Die Abhängigkeitsinjektion ist eine spezielle Version des Musters für die Steuerungsumkehrung (Inversion of Control, IoC), bei dem das Problem, das invertiert wird, der Prozess des Abrufens der erforderlichen Abhängigkeit ist. Mit Dependency Injection ist eine andere Klasse für das Einfügen von Abhängigkeiten in ein Objekt zur Laufzeit verantwortlich.
In der Regel wird beim Instanziieren eines Objekts ein Klassenkonstruktor aufgerufen, und alle Werte, die das Objekt benötigt, werden als Argumente an den Konstruktor übergeben. Dies ist ein Beispiel für Dependency Injection, die als Konstruktorinjektion bezeichnet wird. Die Abhängigkeiten, die das Objekt benötigt, werden in den Konstruktor eingefügt.
Hinweis
Es gibt auch andere Arten der Abhängigkeitsinjektion, z. B. Eigenschaft-Setter-Injektion und Methodenaufrufinjektion, aber sie werden weniger häufig verwendet.
Durch das Angeben von Abhängigkeiten als Schnittstellentypen ermöglicht Dependency Injection eine Entkopplung der konkreten Typen vom Code, der von diesen Typen abhängt. Im Allgemeinen wird ein Container verwendet, der eine Liste von Registrierungen und Zuordnungen zwischen Schnittstellen und abstrakten Typen sowie die konkreten Typen enthält, die diese Typen implementieren oder erweitern.
Abhängigkeitsinjektionscontainer
Wenn eine Klasse die benötigten Objekte nicht direkt instanziiert, muss eine andere Klasse diese Aufgabe übernehmen. Das folgende Beispiel zeigt eine Ansichtsmodellklasse, die Konstruktorargumente erfordert:
public class MainPageViewModel
{
readonly ILoggingService _loggingService;
readonly ISettingsService _settingsService;
public MainPageViewModel(ILoggingService loggingService, ISettingsService settingsService)
{
_loggingService = loggingService;
_settingsService = settingsService;
}
}
In diesem Beispiel erfordert der MainPageViewModel
-Konstruktor zwei Schnittstellenobjektinstanzen als Argumente, die von einer anderen Klasse eingefügt werden. Die einzige Abhängigkeit in der MainPageViewModel
-Klasse bezieht sich auf die Schnittstellentypen. Daher besitzt die MainPageViewModel
-Klasse keine Kenntnis von der Klasse, die für die Instanziierung der Schnittstellenobjekte verantwortlich ist.
Auf ähnliche Weise zeigt das folgende Beispiel eine Seitenklasse, die ein Konstruktorargument erfordert:
public MainPage(MainPageViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
}
In diesem Beispiel erfordert der MainPage
-Konstruktor einen konkreten Typ als Argument, das von einer anderen Klasse eingefügt wird. Die einzige Abhängigkeit in der Klasse MainPage
liegt beim Typ MainPageViewModel
vor. Daher hat die Klasse MainPage
keine Kenntnis der Klasse, die für die Instanziierung des konkreten Typs zuständig ist.
In beiden Fällen wird die Klasse, die dafür zuständig ist, die Abhängigkeiten zu instanziieren und in die abhängige Klasse einzufügen, als Abhängigkeitsinjektionscontainer bezeichnet.
Container mit Abhängigkeitsinjektion verringern die Kopplung zwischen Objekten, indem sie eine Möglichkeit zum Instanziieren von Klasseninstanzen bereitstellen und deren Lebensdauer basierend auf der Konfiguration des Containers verwalten. Während der Objekterstellung fügt der Container alle Abhängigkeiten ein, die das Objekt benötigt. Wenn diese Abhängigkeiten nicht erstellt wurden, erstellt der Container zuerst ihre Abhängigkeiten und löst sie auf.
Die Verwendung eines Dependency Injection-Containers hat mehrere Vorteile:
- Ein Container beseitigt die Notwendigkeit, dass eine Klasse nach ihren Abhängigkeiten suchen und deren Lebensdauer verwalten muss.
- Ein Container ermöglicht die Zuordnung implementierter Abhängigkeiten, ohne dass sich dies auf die Klasse auswirkt.
- Ein Container erleichtert die Testbarkeit, indem Abhängigkeiten simuliert werden können.
- Ein Container erhöht die Wartbarkeit, indem der App neue Klassen auf einfache Weise hinzugefügt werden können.
Im Kontext einer .NET MAUI-App, die das MVVM-Muster verwendet (Model-View-ViewModel, Modellansicht-Ansichtsmodell), wird ein Abhängigkeitsinjektionscontainer normalerweise verwendet, um Ansichten zu registrieren und aufzulösen, Ansichtsmodelle zu registrieren und aufzulösen sowie Dienste zu registrieren und in Ansichtsmodelle einzufügen. Weitere Informationen zum MVVM-Muster finden Sie unter Model-View-ViewModel (MVVM).
Es sind viele Abhängigkeitsinjektionscontainer für .NET verfügbar. .NET MAUI bietet integrierte Unterstützung für die Verwendung von Microsoft.Extensions.DependencyInjection zum Verwalten der Instanziierung von Ansichten, Ansichtsmodellen und Dienstklassen in einer App. Microsoft.Extensions.DependencyInjection ermöglicht das Erstellen von lose gekoppelten Apps und stellt alle Features bereit, die häufig in Dependency Injection-Containern zu finden sind, einschließlich Methoden zum Registrieren von Typzuordnungen und Objektinstanzen, zum Auflösen von Objekten, zum Verwalten von Objektlebensdauern und zum Einfügen abhängiger Objekte in Konstruktoren von Objekten, die aufgelöst werden. Weitere Informationen zu Microsoft.Extensions.DependencyInjection finden Sie unter Dependency Injection in .NET.
Zur Laufzeit muss der Container wissen, welche Implementierung der Abhängigkeiten angefordert wird, damit sie für die angeforderten Objekte instanziiert werden können. Im obigen Beispiel müssen die Schnittstellen ILoggingService
und ISettingsService
aufgelöst werden, bevor das Objekt MainPageViewModel
instanziiert werden kann. Dies bedeutet, dass der Container die folgenden Aktionen durchführt:
- Entscheiden, wie ein Objekt instanziiert werden soll, das die Schnittstelle implementiert. Dies wird als Registrierung bezeichnet. Weitere Informationen finden Sie unter Registrierung.
- Instanziieren des Objekts, das die erforderliche Schnittstelle und das
MainPageViewModel
-Objekt implementiert. Dies wird als Auflösung bezeichnet. Weitere Informationen finden Sie unter Auflösung.
Schließlich stellt eine App die Verwendung des Objekts MainPageViewModel
ein, und es wird für die automatische Speicherbereinigung (Garbage Collection, GC) verfügbar. An diesem Punkt sollte der Garbage Collector alle kurzlebigen Schnittstellenimplementierungen löschen, wenn andere Klassen nicht dieselben Instanzen verwenden.
Registrierung
Bevor Abhängigkeiten in ein Objekt eingefügt werden können, müssen die Typen für die Abhängigkeiten zunächst beim Container registriert werden. Beim Registrieren eines Typs wird meist ein konkreter Typ oder eine Schnittstelle und ein konkreter Typ, der die Schnittstelle implementiert, an den Container übergeben.
Es gibt zwei Hauptansätze zum Registrieren von Typen und Objekten mit dem Container:
- Registrieren Sie einen Typ oder eine Zuordnung beim Container. Dies wird als vorübergehende Registrierung bezeichnet. Bei Bedarf erstellt der Container eine Instanz des angegebenen Typs.
- Registrieren Sie ein vorhandenes Objekt im Container als Singleton. Bei Bedarf gibt der Container einen Verweis auf das vorhandene Objekt zurück.
Achtung
Abhängigkeitsinjektionscontainer eignen sich nicht immer für eine .NET MAUI-App. Die Abhängigkeitsinjektion führt zu zusätzlicher Komplexität und weiteren Anforderungen, die für kleinere Apps möglicherweise nicht geeignet oder nützlich sind. Wenn eine Klasse keine Abhängigkeiten aufweist oder keine Abhängigkeit für andere Typen darstellt, ist es möglicherweise nicht sinnvoll, sie im Container zu platzieren. Wenn eine Klasse über eine einzelne Gruppe von Abhängigkeiten verfügt, die für den Typ integral sind und sich nie ändern, ist es möglicherweise ebenfalls nicht sinnvoll, sie in den Container zu platzieren.
Die Registrierung von Typen, die eine Abhängigkeitsinjektion erfordern, sollte in einer einzigen Methode in Ihrer App ausgeführt werden. Diese Methode sollte frühzeitig im Lebenszyklus der App aufgerufen werden, um sicherzustellen, dass die Abhängigkeiten zwischen den Klassen beachtet werden. Apps sollten dies normalerweise in der CreateMauiApp
-Methode in der MauiProgram
-Klasse ausführen. Die MauiProgram
-Klasse ruft die CreateMauiApp
-Methode auf, um ein MauiAppBuilder-Objekt zu erstellen. Das MauiAppBuilder-Objekt verfügt über eine Services-Eigenschaft vom Typ IServiceCollection, die einen Ort zum Registrieren Ihrer Typen bereitstellt, z. B. Ansichten, Ansichtsmodelle und Dienste für die Abhängigkeitsinjektion:
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
builder.Services.AddTransient<ILoggingService, LoggingService>();
builder.Services.AddTransient<ISettingsService, SettingsService>();
builder.Services.AddSingleton<MainPageViewModel>();
builder.Services.AddSingleton<MainPage>();
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
Typen, die bei der Services-Eigenschaft registriert sind, werden dem Abhängigkeitsinjektionscontainer bereitgestellt, wenn MauiAppBuilder.Build() aufgerufen wird.
Beim Registrieren von Abhängigkeiten müssen Sie alle Abhängigkeiten registrieren, einschließlich aller Typen, die die Abhängigkeiten erfordern. Wenn Sie also über ein Ansichtsmodell verfügen, das eine Abhängigkeit als Konstruktorparameter verwendet, müssen Sie das Ansichtsmodell zusammen mit allen ihren Abhängigkeiten registrieren. Auf ähnliche Weise müssen Sie bei einer Ansicht, die eine Abhängigkeit von einem Ansichtsmodell als Konstruktorparameter verwendet, die Ansicht und das Ansichtsmodell zusammen mit allen ihren Abhängigkeiten registrieren.
Tipp
Ein Abhängigkeitsinjektionscontainer eignet sich ideal zum Erstellen von Ansichtsmodellinstanzen. Wenn ein Ansichtsmodell Abhängigkeiten aufweist, verwaltet er die Erstellung und Einfügung aller erforderlichen Dienste. Sie müssen lediglich sicherstellen, dass Sie Ihre Ansichtsmodelle und alle potenziellen Abhängigkeiten in der CreateMauiApp
-Methode in der MauiProgram
-Klasse registrieren.
In einer Shell-App müssen Sie Ihre Seiten nicht mit dem Container zum Einfügen von Abhängigkeiten registrieren, es sei denn, Sie möchten die Lebensdauer der Seite relativ zum Container mit den AddSingleton
Methoden AddTransient
oder AddScoped
Methoden beeinflussen. Weitere Informationen finden Sie unter Abhängigkeitsdauer.
Abhängigkeitslebensdauer
Je nach den Anforderungen Ihrer App müssen Sie möglicherweise Abhängigkeiten mit unterschiedlichen Lebensdauern registrieren. In der folgenden Tabelle sind die wichtigsten Methoden aufgeführt, die Sie zum Registrieren von Abhängigkeiten verwenden können. Dabei ist auch die jeweilige Registrierungslebensdauer angegeben:
Methode | Beschreibung |
---|---|
AddSingleton<T> |
Erstellt eine einzelne Instanz des Objekts, die während der gesamten Lebensdauer der App erhalten bleibt. |
AddTransient<T> |
Erstellt eine neue Instanz des Objekts, wenn dies während der Auflösung angefordert wird. Vorübergehende Objekte verfügen nicht über eine vordefinierte Lebensdauer, sondern folgen in der Regel der Lebensdauer ihres Hosts. |
AddScoped<T> |
Erstellt eine Instanz des Objekts, die dieselbe Lebensdauer wie ihr Host hat. Wenn der Host den Geltungsbereich verlässt, ist dies auch bei der Abhängigkeit der Fall. Das mehrfache Auflösen derselben Abhängigkeit innerhalb desselben Geltungsbereichs führt daher zu derselben Instanz, während das Auflösen derselben Abhängigkeit in verschiedenen Geltungsbereichen unterschiedliche Instanzen liefert. |
Hinweis
Wenn ein Objekt nicht von einer Schnittstelle erbt, z. B. eine Ansicht oder ein Ansichtsmodell, muss nur der konkrete Typ für die Methode AddSingleton<T>
, AddTransient<T>
oder AddScoped<T>
angegeben werden.
Die MainPageViewModel
-Klasse wird in der Nähe des Stamms der App verwendet und sollte immer verfügbar sein. Deshalb empfiehlt sich eine Registrierung mit AddSingleton<T>
. Die Navigation zu anderen Ansichtsmodellen kann situationsbedingt erfolgen, oder die Ansichtsmodelle können später in einer App verwendet werden. Wenn Sie über einen Typ verfügen, der möglicherweise nicht immer verwendet wird oder der viel Arbeitsspeicher oder Rechenleistung benötigt oder Just-in-Time-Daten erfordert, ist die Registrierung mit AddTransient<T>
möglicherweise besser geeignet.
Eine weitere gängige Vorgehensweise zum Registrieren von Abhängigkeiten ist die Verwendung der Methoden AddSingleton<TService, TImplementation>
, AddTransient<TService, TImplementation>
oder AddScoped<TService, TImplementation>
. Diese Methoden haben zwei Typen: die Schnittstellendefinition und die konkrete Implementierung. Diese Art der Registrierung eignet sich am besten für Fälle, in denen Sie Dienste basierend auf Schnittstellen implementieren.
Nachdem alle Typen registriert wurden, sollte MauiAppBuilder.Build() aufgerufen werden, um das MauiApp-Objekt zu erstellen und den Abhängigkeitsinjektionscontainer mit allen registrierten Typen aufzufüllen.
Wichtig
Nachdem MauiAppBuilder.Build() aufgerufen wurde, sind die Typen, die mit dem Abhängigkeitsinjektionscontainer registriert sind, unveränderlich und können nicht mehr aktualisiert oder geändert werden.
Registrieren von Abhängigkeiten mit einer Erweiterungsmethode
Die MauiApp.CreateBuilder-Methode erstellt ein MauiAppBuilder-Objekt, das zum Registrieren von Abhängigkeiten verwendet werden kann. Wenn Ihre App viele Abhängigkeiten registrieren muss, können Sie Erweiterungsmethoden erstellen, um einen organisierten und verwalteten Registrierungsworkflow bereitzustellen:
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
=> MauiApp.CreateBuilder()
.UseMauiApp<App>()
.RegisterServices()
.RegisterViewModels()
.RegisterViews()
.Build();
public static MauiAppBuilder RegisterServices(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddTransient<ILoggingService, LoggingService>();
mauiAppBuilder.Services.AddTransient<ISettingsService, SettingsService>();
// More services registered here.
return mauiAppBuilder;
}
public static MauiAppBuilder RegisterViewModels(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddSingleton<MainPageViewModel>();
// More view-models registered here.
return mauiAppBuilder;
}
public static MauiAppBuilder RegisterViews(this MauiAppBuilder mauiAppBuilder)
{
mauiAppBuilder.Services.AddSingleton<MainPage>();
// More views registered here.
return mauiAppBuilder;
}
}
In diesem Beispiel verwenden die drei Registrierungserweiterungsmethoden die MauiAppBuilder-Instanz, um auf die Services-Eigenschaft zuzugreifen, damit die Abhängigkeiten registriert werden.
Lösung
Nachdem ein Typ registriert wurde, kann er aufgelöst oder als Abhängigkeit eingefügt werden. Wenn ein Typ aufgelöst wird und der Container eine neue Instanz erstellen muss, fügt er alle Abhängigkeiten in die Instanz ein.
Wenn ein Typ aufgelöst wird, tritt im Allgemeinen eines von drei Szenarien auf:
- Wenn der Typ nicht registriert wurde, löst der Container eine Ausnahme aus.
- Wenn der Typ als Singleton registriert wurde, gibt der Container die Singleton-Instanz zurück. Wenn der Typ zum ersten Mal aufgerufen wird, erstellt der Container ihn bei Bedarf und verwaltet einen Verweis darauf.
- Wenn der Typ als vorübergehend registriert wurde, gibt der Container eine neue Instanz zurück und verwaltet keinen Verweis darauf.
.NET MAUI unterstützt die automatische und die explizite Abhängigkeitsauflösung. Die automatische Abhängigkeitsauflösung verwendet die Konstruktorinjektion, ohne die Abhängigkeit explizit vom Container anzufordern. Die explizite Abhängigkeitsauflösung erfolgt bei Bedarf, indem explizit eine Abhängigkeit vom Container angefordert wird.
Automatische Abhängigkeitsauflösung
Die automatische Abhängigkeitsauflösung erfolgt in Apps, die die .NET MAUI-Shell verwenden, vorausgesetzt, Sie haben den Typ der Abhängigkeit und den Typ, der die Abhängigkeit verwendet, mit dem Abhängigkeitsinjektionscontainer registriert.
Während der Shell-basierten Navigation sucht .NET MAUI nach Seitenregistrierungen. Falls diese vorhanden sind, erstellt .NET MAUI die jeweilige Seite und fügt die entsprechenden Abhängigkeiten in ihren Konstruktor ein:
public MainPage(MainPageViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
}
In diesem Beispiel empfängt der MainPage
-Konstruktor eine MainPageViewModel
-Instanz, die eingefügt wird. In die Instanz MainPageViewModel
werden wiederum die Instanzen ILoggingService
und ISettingsService
eingefügt:
public class MainPageViewModel
{
readonly ILoggingService _loggingService;
readonly ISettingsService _settingsService;
public MainPageViewModel(ILoggingService loggingService, ISettingsService settingsService)
{
_loggingService = loggingService;
_settingsService = settingsService;
}
}
Darüber hinaus fügt .NET MAUI in einer Shell-basierten App Abhängigkeiten in Detailseiten ein, die bei der Routing.RegisterRoute-Methode registriert sind.
Explizite Abhängigkeitsauflösung
Eine Shell-basierte App kann keine Konstruktoreinfügung verwenden, wenn ein Typ nur einen parameterlosen Konstruktor verfügbar macht. Alternativ gilt, dass Sie die explizite Abhängigkeitsauflösung verwenden müssen, wenn Ihre App die Shell nicht verwendet.
Auf den Abhängigkeitsinjektionscontainer kann explizit von einem Element über die Handler.MauiContext.Service
-Eigenschaft, die den Typ IServiceProvider hat, zugegriffen werden:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
HandlerChanged += OnHandlerChanged;
}
void OnHandlerChanged(object sender, EventArgs e)
{
BindingContext = Handler.MauiContext.Services.GetService<MainPageViewModel>();
}
}
Dieser Ansatz kann nützlich sein, wenn Sie eine Abhängigkeit von einem Element oder von außerhalb des Konstruktors von einem Element auflösen müssen. In diesem Beispiel stellt der Zugriff auf den Abhängigkeitsinjektionscontainer im HandlerChanged
-Ereignishandler sicher, dass ein Handler für die Seite festgelegt wurde und daher die Handler
-Eigenschaft nicht null
sein wird.
Warnung
Die Handler
-Eigenschaft für Ihr Element
könnte null
sein. Berücksichtigen Sie daher diese potenzielle Situation. Weitere Informationen finden Sie unter Handler-Lebenszyklus.
In einem Ansichtsmodell ist der Zugriff auf den Abhängigkeitsinjektionscontainer explizit über die Handler.MauiContext.Service
-Eigenschaft von Application.Current.MainPage
möglich:
public class MainPageViewModel
{
readonly ILoggingService _loggingService;
readonly ISettingsService _settingsService;
public MainPageViewModel()
{
_loggingService = Application.Current.MainPage.Handler.MauiContext.Services.GetService<ILoggingService>();
_settingsService = Application.Current.MainPage.Handler.MauiContext.Services.GetService<ISettingsService>();
}
}
In einem Ansichtsmodell kann der Container zum Einfügen von Abhängigkeiten explizit über die Handler.MauiContext.Service
Eigenschaft der Window.Page
:
public class MainPageViewModel
{
readonly ILoggingService _loggingService;
readonly ISettingsService _settingsService;
public MainPageViewModel()
{
_loggingService = Application.Current.Windows[0].Page.Handler.MauiContext.Services.GetService<ILoggingService>();
_settingsService = Application.Current.Windows[0].Page.Handler.MauiContext.Services.GetService<ISettingsService>();
}
}
Ein Nachteil dieses Ansatzes ist, dass das Ansichtsmodell jetzt eine Abhängigkeit vom Typ Application hat. Dieser Nachteil kann jedoch beseitigt werden, indem ein IServiceProvider-Argument an den Ansichtsmodellkonstruktor übergeben wird. IServiceProvider wird durch die automatische Abhängigkeitsauflösung aufgelöst, ohne dass eine Registrierung beim Abhängigkeitsinjektionscontainer erforderlich ist. Bei diesem Ansatz kann ein Typ und seine IServiceProvider-Abhängigkeit automatisch aufgelöst werden, vorausgesetzt, der Typ ist beim Abhängigkeitsinjektionscontainer registriert. IServiceProvider kann dann für die explizite Abhängigkeitsauflösung verwendet werden:
public class MainPageViewModel
{
readonly ILoggingService _loggingService;
readonly ISettingsService _settingsService;
public MainPageViewModel(IServiceProvider serviceProvider)
{
_loggingService = serviceProvider.GetService<ILoggingService>();
_settingsService = serviceProvider.GetService<ISettingsService>();
}
}
Darüber hinaus kann auf jeder Plattform über die Eigenschaft IPlatformApplication.Current.Services
auf eine IServiceProvider-Instanz zugegriffen werden.
Einschränkungen bei XAML-Ressourcen
Ein häufiges Szenario besteht darin, eine Seite mit dem Abhängigkeitsinjektionscontainer zu registrieren und die automatische Abhängigkeitsauflösung zu verwenden, um sie in den App
-Konstruktor einzufügen und als Wert der MainPage
-Eigenschaft festzulegen:
public App(MyFirstAppPage page)
{
InitializeComponent();
MainPage = page;
}
Ein häufiges Szenario besteht darin, eine Seite mit dem Abhängigkeitseinfügungscontainer zu registrieren und die automatische Abhängigkeitsauflösung zu verwenden, um sie in den App
Konstruktor einzufügen und als erste Seite festzulegen, die in der App angezeigt wird:
MyFirstAppPage _firstPage;
public App(MyFirstAppPage page)
{
InitializeComponent();
_firstPage = page;
}
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(_firstPage);
}
Wenn MyFirstAppPage
jedoch in diesem Szenario versucht, auf eine StaticResource
-Instanz zuzugreifen, die in XAML im App
-Ressourcenverzeichnis deklariert wurde, wird eine XamlParseException-Ausnahme mit einer Meldung ausgelöst, die Position {row}:{column}. StaticResource not found for key {key}
ähnelt. Dies geschieht, da die Seite, die durch die Konstruktoreinfügung aufgelöst wurde, erstellt wurde, bevor die XAML-Ressourcen auf Anwendungsebene initialisiert wurden.
Sie können dieses Problem umgehen, indem Sie eine IServiceProvider-Instanz in Ihre App
-Klasse einfügen und dann damit die Seite innerhalb der App
-Klasse auflösen:
public App(IServiceProvider serviceProvider)
{
InitializeComponent();
MainPage = serviceProvider.GetService<MyFirstAppPage>();
}
MyFirstAppPage _firstPage;
public App(IServiceProvider serviceProvider)
{
InitializeComponent();
_firstPage = serviceProvider.GetService<MyFirstAppPage>();
}
protected override Window CreateWindow(IActivationState? activationState)
{
return new Window(_firstPage);
}
Dieser Ansatz erzwingt die Erstellung und Initialisierung der XAML-Objektstruktur, bevor die Seite aufgelöst wird.