2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Dieser Artikel verwendet das WPF Gallery-Projekt, um die zugehörigen Konzepte der Abhängigkeitsinjektion und die Durchführung der Abhängigkeitsinjektion in WPF kennenzulernen.
Dependency Injection (DI) ist ein Entwurfsmuster, das zur Implementierung des Inversion of Control (IoC)-Prinzips verwendet wird. Der Hauptzweck der Abhängigkeitsinjektion besteht darin, die Erstellung von Objekten und die Verwaltung von Abhängigkeiten zwischen Objekten aus dem Objekt heraus in einen externen Container oder ein Framework zu übertragen und so die Wartbarkeit, Testbarkeit und Flexibilität des Codes zu verbessern.
Das Kernkonzept der Abhängigkeitsinjektion
Arten der Abhängigkeitsinjektion
Konstruktorinjektion: Das abhängige Objekt wird durch den Konstruktor der Klasse übergeben.
public class OrderService
{
private readonly IProductRepository _productRepository;
public OrderService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
}
Immobilienspritze: Abhängige Objekte werden über die öffentlichen Eigenschaften der Klasse übergeben.
public class OrderService
{
public IProductRepository ProductRepository { get; set; }
}
Methode Injektion: Das abhängige Objekt wird über den Methodenparameter der Klasse übergeben.
public class OrderService
{
public void ProcessOrder(IProductRepository productRepository)
{
// 使用 productRepository 处理订单
}
}
Dependency Injection (DI) ist ein Entwurfsmuster, mit dem die Erstellung von Objekten und die Verwaltung von Abhängigkeiten zwischen Objekten aus dem Objekt heraus auf einen externen Container oder ein Framework übertragen werden können. Es gibt mehrere wichtige Gründe und Vorteile für die Abhängigkeitsinjektion:
In diesem Artikel erfahren Sie anhand des WPF Gallery-Projekts, wie Sie die Abhängigkeitsinjektion in der WPF-Codeadresse verwenden:
https://github.com/microsoft/WPF-Samples/blob/main/SampleApplications/WPFGallery
Um die Abhängigkeitsinjektion in diesem Projekt zu implementieren, werden diese beiden Pakete verwendet:
Schauen Sie sich zunächst den Inhalt von App.xaml.cs an:
public partial class App : Application
{
private static readonly IHost _host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<MainWindow>();
services.AddSingleton<MainWindowViewModel>();
services.AddTransient<DashboardPage>();
services.AddTransient<DashboardPageViewModel>();
services.AddTransient<ButtonPage>();
services.AddTransient<ButtonPageViewModel>();
services.AddTransient<CheckBoxPage>();
services.AddTransient<CheckBoxPageViewModel>();
services.AddTransient<ComboBoxPage>();
services.AddTransient<ComboBoxPageViewModel>();
services.AddTransient<RadioButtonPage>();
services.AddTransient<RadioButtonPageViewModel>();
services.AddTransient<SliderPage>();
services.AddTransient<SliderPageViewModel>();
services.AddTransient<CalendarPage>();
services.AddTransient<CalendarPageViewModel>();
services.AddTransient<DatePickerPage>();
services.AddTransient<DatePickerPageViewModel>();
services.AddTransient<TabControlPage>();
services.AddTransient<TabControlPageViewModel>();
services.AddTransient<ProgressBarPage>();
services.AddTransient<ProgressBarPageViewModel>();
services.AddTransient<MenuPage>();
services.AddTransient<MenuPageViewModel>();
services.AddTransient<ToolTipPage>();
services.AddTransient<ToolTipPageViewModel>();
services.AddTransient<CanvasPage>();
services.AddTransient<CanvasPageViewModel>();
services.AddTransient<ExpanderPage>();
services.AddTransient<ExpanderPageViewModel>();
services.AddTransient<ImagePage>();
services.AddTransient<ImagePageViewModel>();
services.AddTransient<DataGridPage>();
services.AddTransient<DataGridPageViewModel>();
services.AddTransient<ListBoxPage>();
services.AddTransient<ListBoxPageViewModel>();
services.AddTransient<ListViewPage>();
services.AddTransient<ListViewPageViewModel>();
services.AddTransient<TreeViewPage>();
services.AddTransient<TreeViewPageViewModel>();
services.AddTransient<LabelPage>();
services.AddTransient<LabelPageViewModel>();
services.AddTransient<TextBoxPage>();
services.AddTransient<TextBoxPageViewModel>();
services.AddTransient<TextBlockPage>();
services.AddTransient<TextBlockPageViewModel>();
services.AddTransient<RichTextEditPage>();
services.AddTransient<RichTextEditPageViewModel>();
services.AddTransient<PasswordBoxPage>();
services.AddTransient<PasswordBoxPageViewModel>();
services.AddTransient<ColorsPage>();
services.AddTransient<ColorsPageViewModel>();
services.AddTransient<LayoutPage>();
services.AddTransient<LayoutPageViewModel>();
services.AddTransient<AllSamplesPage>();
services.AddTransient<AllSamplesPageViewModel>();
services.AddTransient<BasicInputPage>();
services.AddTransient<BasicInputPageViewModel>();
services.AddTransient<CollectionsPage>();
services.AddTransient<CollectionsPageViewModel>();
services.AddTransient<MediaPage>();
services.AddTransient<MediaPageViewModel>();
services.AddTransient<NavigationPage>();
services.AddTransient<NavigationPageViewModel>();
services.AddTransient<TextPage>();
services.AddTransient<TextPageViewModel>();
services.AddTransient<DateAndTimePage>();
services.AddTransient<DateAndTimePageViewModel>();
services.AddTransient<StatusAndInfoPage>();
services.AddTransient<StatusAndInfoPageViewModel>();
services.AddTransient<SamplesPage>();
services.AddTransient<SamplesPageViewModel>();
services.AddTransient<DesignGuidancePage>();
services.AddTransient<DesignGuidancePageViewModel>();
services.AddTransient<UserDashboardPage>();
services.AddTransient<UserDashboardPageViewModel>();
services.AddTransient<TypographyPage>();
services.AddTransient<TypographyPageViewModel>();
services.AddSingleton<IconsPage>();
services.AddSingleton<IconsPageViewModel>();
services.AddSingleton<SettingsPage>();
services.AddSingleton<SettingsPageViewModel>();
services.AddSingleton<AboutPage>();
services.AddSingleton<AboutPageViewModel>();
}).Build();
[STAThread]
public static void Main()
{
_host.Start();
App app = new();
app.InitializeComponent();
app.MainWindow = _host.Services.GetRequiredService<MainWindow>();
app.MainWindow.Visibility = Visibility.Visible;
app.Run();
}
}
Was ist IHost?
In C#,IHost
ist eine Schnittstelle, die in .NET zum Erstellen und Konfigurieren von Anwendungen verwendet wirdHost
Konzept abstrakt.IHost
Eine Schnittstelle definiert eine Sammlung von Diensten und Komponenten, die zum Starten, Ausführen und Verwalten einer Anwendung erforderlich sind. Es wird normalerweise mit ASP.NET Core-Anwendungen verwendet, funktioniert aber auch mit anderen Arten von .NET-Anwendungen, wie Konsolenanwendungen oder WPF-Programmen.
IHost
Die Schnittstelle besteht ausHostBuilder
Klassenimplementierung, die die Erstellung und Konfiguration von ermöglichtIHost
Instanzmethoden.HostBuilder
Ermöglicht Ihnen das Hinzufügen verschiedener Dienste wie Protokollierung, Konfiguration, Abhängigkeitsinjektionscontainer usw. sowie das Konfigurieren des Start- und Stoppverhaltens Ihrer Anwendung.
Bietet praktische Methoden zum Erstellen von Microsoft.Extensions.Hosting.IHostBuilder-Instanzen mit vorkonfigurierten Standardwerten.
Gibt einen IHostBuilder zurück.
Fügen Sie dem Container Dienste hinzu. Dieser Vorgang kann mehrmals aufgerufen werden und seine Ergebnisse sind kumulativ.
Die Bedeutung des Parameters configureDelegate besteht darin, den Delegaten von Microsoft.Extensions.DependencyInjection.IServiceCollection zu konfigurieren.
Diese Sammlung wird zum Erstellen von System.IServiceProvider verwendet.
Der Delegat erfordert zwei Parametertypen: HostBuilderContext und IServiceCollection, die keinen Rückgabewert haben.
Hier wird ein Lambda-Ausdruck übergeben, der den Delegatentyp erfüllt.
In C#,() => {}
Ist eine Syntax für Lambda-Ausdrücke. Lambda-Ausdrücke sind ein einfacher Delegaten-Wrapper, mit dem Sie eine anonyme Methode definieren und als Parameter an eine Methode übergeben können, die Delegaten oder Ausdrucksbäume unterstützt.
Lambda-Ausdrücke bieten eine übersichtliche Möglichkeit zum Definieren von Methoden und sind insbesondere dann nützlich, wenn Sie Methoden als Parameter an andere Methoden übergeben müssen.
Beim Hinzufügen von Diensten gibt es hier zwei Lebenszyklen: Neben AddSingleton und AddTransient gibt es auch AddScoped.
Diese Methoden definieren den Lebenszyklus des Dienstes, d. h. wie Dienstinstanzen in der Anwendung erstellt und verwaltet werden.
AddSingleton
AddTransient
AddScoped
diese Dienste nutzen
In der Hauptfunktion:
Start-up_host
,passieren_host.Services.GetRequiredService<MainWindow>();
Rufen Sie die MainWindow-Instanz ab.
Sehen Sie sich am Beispiel der MainWindow-Klasse den Konstruktor von MainWindow in MainWindow.xaml.cs an:
public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvider, INavigationService navigationService)
{
_serviceProvider = serviceProvider;
ViewModel = viewModel;
DataContext = this;
InitializeComponent();
Toggle_TitleButtonVisibility();
_navigationService = navigationService;
_navigationService.Navigating += OnNavigating;
_navigationService.SetFrame(this.RootContentFrame);
_navigationService.Navigate(typeof(DashboardPage));
WindowChrome.SetWindowChrome(
this,
new WindowChrome
{
CaptionHeight = 50,
CornerRadius = default,
GlassFrameThickness = new Thickness(-1),
ResizeBorderThickness = ResizeMode == ResizeMode.NoResize ? default : new Thickness(4),
UseAeroCaptionButtons = true
}
);
this.StateChanged += MainWindow_StateChanged;
}
Nach dem Entfernen der für dieses Thema irrelevanten Inhalte sieht es wie folgt aus:
public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvider, INavigationService navigationService)
{
_serviceProvider = serviceProvider;
ViewModel = viewModel;
_navigationService = navigationService;
}
Ist Ihnen aufgefallen, dass Sie diese Objekte nicht mehr selbst neu erstellen müssen? Die Erstellung dieser Objekte wird vom Abhängigkeitsinjektionscontainer verwaltet. Wenn diese Objekte benötigt werden, können sie wie bisher über den Konstruktor eingefügt werden.
Wenn keine Abhängigkeitsinjektion verwendet wird, könnte es so aussehen:
public MainWindow()
{
_serviceProvider = new IServiceProvider();
ViewModel = new MainWindowViewModel();
_navigationService = new INavigationService();
}
In diesem Artikel wird zunächst das Konzept der Abhängigkeitsinjektion vorgestellt, dann erklärt, warum eine Abhängigkeitsinjektion erforderlich ist, und schließlich wird über das WPF Gallery-Projekt erläutert, wie die Abhängigkeitsinjektion in WPF verwendet wird.
1. [WPF-Samples/Beispielanwendungen/WPFGallery auf der Hauptseite · Microsoft/WPF-Samples (github.com)](https://github.com/microsoft/WPF-Samples/tree/main/Beispielanwendungen/WPFGallery)