.NET Core 3.0 中 WPF 的依赖注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/54877352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 14:11:08  来源:igfitidea点击:

Dependency Injection in .NET Core 3.0 for WPF

wpf.net-core.net-core-3.0

提问by user842818

I'm quite familiar with ASP.NET Core and the support for dependency injection out of the box. Controllers can require dependencies by adding a parameter in their constructor. How can dependencies be achieved in WPF UserControls? I tried adding a parameter to the constructor, but that didn't work. I love the IOC concept and would prefer to bring this forward to WPF.

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

回答by maytham-???????

I have recently come across this requirement to my project and I solved it this way.

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

For Dependency Injection in .NET Core 3.0 for WPF. After you create a WPF core 3 project in your solution, you need to install/add nuget packages:

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

Microsoft.Extensions.DependencyInjection

In my case I created a class that I want to use for logging called it LogBase, so in your App class add following and ya this is just a basic example:

就我而言,我创建了一个我想用于日志记录的类,称为 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();
}

In your App.xaml, add Startup="OnStartup" so it looks like this:

在您的 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>

So in your MainWindow.xaml.cs you inject ILogBase in constructor like this:

因此,在 MainWindow.xaml.cs 中,您将 ILogBase 注入到构造函数中,如下所示:

private readonly ILogBase _log;

public MainWindow(ILogBase log)
{
    _log = log;

    ...etc.. you can use _log over all in this class

in my LogBase class I use any logger I like in my way.

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

I have added all this together in githubrepo.

我已经在githubrepo 中添加了所有这些。



Meanwhile I have been asked how to use injection inside user control, I come with this solution if some one get the benefit of it. Check it here.

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

回答by Robert J?rgensgaard Engdahl

In WPF you use a pattern called Model-View-ViewModel (MVVM for short). Your dependencies are injected into the view-model (using same IoC frameworks as you use in ASP.NET, e.g. AutoFac) and your views (UserControls) are registered as data templates to your view-models.

在 WPF 中,您使用一种称为 Model-View-ViewModel(简称 MVVM)的模式。您的依赖项被注入到视图模型中(使用与您在 ASP.NET 中使用的相同的 IoC 框架,例如 AutoFac),并且您的视图 (UserControls) 被注册为视图模型的数据模板。

In that way you structure your application around view-models and the views (that depend on the view models) are resolved as if the view-model depended on the view. Views may access their view-model through their DataContext property. So you can use the view-model as a facade to inject whatever to your views.

通过这种方式,您可以围绕视图模型构建应用程序,并且视图(依赖于视图模型)被解析为好像视图模型依赖于视图一样。视图可以通过它们的 DataContext 属性访问它们的视图模型。因此,您可以使用视图模型作为外观将任何内容注入您的视图。

回答by Mark Feldman

Generally speaking, you don't. You use dependency injection in your view models and you then use data binding to bind your views to those instead.

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

That's not to say it can't be done. MVVM Light, for example, creates an injector class and then declares an instance of it in App.xaml, which is almost the same as declaring a global variable:

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

<Application.Resources>
    <ResourceDictionary>
        <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:MyMvvmProject.ViewModel" />
    </ResourceDictionary>
</Application.Resources>

Windows and user controls that are part of the visual tree can bind to application resources, so in that framework the main window typically binds to the view model like so:

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

<Window x:Class="MyMvvmProject.MainWindow"
    ...
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}">

...where Mainis a property of the locator class:

...哪里Main是定位器类的属性:

public MainViewModel Main
{
    get
    {
        return ServiceLocator.Current.GetInstance<MainViewModel>();
    }
}

This is not very good IoC because it puts all of your injectables in a single class, in practice you would break it up into specialized factories etc at various levels.

这不是很好的 IoC,因为它将所有的可注入对象放在一个类中,在实践中,您会将它分解为各个级别的专门工厂等。

But seriously, don't do any of this. Use DI in your view model layer and use loose data-binding to couple it to your view. This will allow you to exploit the full power of dependency injection, partly by de-coupling it from a layer where it's not needed and partly by allowing flexibility to re-configure your dependencies for different environments i.e. web, desktop, mobile and especially unit testing where views don't get created at all.

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

(Disclaimer: I haven't yet used .NET Core for WPF, so what I've presented here may be a bit .NET-specific, but the general principles remain).

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

回答by OptimusPrime

Good question, one cannot have controls without non parameterized constructor in xaml. If you want, you need to instantiate it from code, but xaml won't call that constructor.

好问题,如果没有 xaml 中的非参数化构造函数,就不能拥有控件。如果需要,您需要从代码中实例化它,但 xaml 不会调用该构造函数。

回答by Luká? Koten

You have to use code behind in that case. But think twice if it is really necessary to have a dependency in UserControl or any other class instantiated from xaml.

在这种情况下,您必须使用隐藏代码。但是,如果真的有必要在 UserControl 或从 xaml 实例化的任何其他类中具有依赖项,请三思。