.NET Core 3.0 中 WPF 的依赖注入

use*_*818 16 wpf .net-core .net-core-3.0

我非常熟悉 ASP.NET Core 和开箱即用的依赖注入支持。控制器可以通过在其构造函数中添加参数来要求依赖项。如何在 WPF UserControls 中实现依赖关系?我尝试向构造函数添加一个参数,但这不起作用。我喜欢 IOC 的概念,并且更愿意将其引入 WPF。

may*_*ʎɐɯ 32

我最近在我的项目中遇到了这个要求,我是这样解决的。

用于 WPF 的 .NET Core 3.0 中的依赖注入。在解决方案中创建 WPF Core 3 项目后,需要安装/添加 NuGet 包:

Microsoft.Extensions.DependencyInjection
Run Code Online (Sandbox Code Playgroud)

就我而言,我创建了一个名为 LogBase 的类,我想将其用于日志记录,因此在您的 App 类中,添加以下内容(这只是一个基本示例):

private readonly ServiceProvider _serviceProvider;

public App()
{
    var serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
    _serviceProvider = serviceCollection.BuildServiceProvider();
}
    
private void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ILogBase>(new LogBase(new FileInfo($@"C:\temp\log.txt")));
    services.AddSingleton<MainWindow>();
}
    
private void OnStartup(object sender, StartupEventArgs e)
{
    var mainWindow = _serviceProvider.GetService<MainWindow>();
    mainWindow.Show();
}
Run Code Online (Sandbox Code Playgroud)

在您的 App.xaml 中,添加 Startup="OnStartup" 如下所示:

<Application x:Class="VaultDataStore.Wpf.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:VaultDataStore.Wpf"
             Startup="OnStartup">
    <Application.Resources>
        
    </Application.Resources>
</Application>
Run Code Online (Sandbox Code Playgroud)

因此,在 MainWindow.xaml.cs 中,像这样在构造函数中注入 ILogBase:

private readonly ILogBase _log;

public MainWindow(ILogBase log)
{
    _log = log;

    ...etc.. you can use _log over all in this class
Run Code Online (Sandbox Code Playgroud)

在我的 LogBase 类中,我使用任何我喜欢的记录器。

我已经在这个 GitHub repo 中添加了所有这些。


同时,有人问我如何在用户控件中使用注入。如果有人从中受益,我会提出这个解决方案。在这里检查。


Mar*_*man 1

一般来说,你不需要。您可以在视图模型中使用依赖注入,然后使用数据绑定将视图绑定到这些视图。

这并不是说它不能完成。例如,MVVM Light 创建一个注入器类,然后在 App.xaml 中声明它的实例,这与声明全局变量几乎相同:

<Application.Resources>
    <ResourceDictionary>
        <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:MyMvvmProject.ViewModel" />
    </ResourceDictionary>
</Application.Resources>
Run Code Online (Sandbox Code Playgroud)

作为可视化树一部分的窗口和用户控件可以绑定到应用程序资源,因此在该框架中,主窗口通常绑定到视图模型,如下所示:

<Window x:Class="MyMvvmProject.MainWindow"
    ...
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}">
Run Code Online (Sandbox Code Playgroud)

...其中Main是定位器类的属性:

public MainViewModel Main
{
    get
    {
        return ServiceLocator.Current.GetInstance<MainViewModel>();
    }
}
Run Code Online (Sandbox Code Playgroud)

这不是很好的 IoC,因为它将所有可注入的东西放在一个类中。在实践中,你可以将其分解为不同级别的专业工厂等。

但说真的,不要做任何这样的事情。在视图模型层中使用 DI 并使用松散数据绑定将其耦合到视图。这将使您能够充分利用依赖项注入的功能,部分是通过将其与不需要的层解耦,部分是通过允许灵活地为不同环境(即 Web、桌面、移动,尤其是单元测试)重新配置依赖项根本不会创建视图。

(免责声明:我尚未将 .NET Core 用于 WPF,因此我在这里介绍的内容可能有点特定于 .NET,但一般原则仍然存在)。