C# WPF中页视图模型的依赖项注入
我正在使用.NETCore3.1创建一个WPF应用程序 我过去开发过ASP.Net应用程序,我很高兴能在WPF中使用它。我做了一些搜索,发现WPF中的DI不像ASP.Net中的DI那么简单,这意味着您必须注册视图和视图模型 我的结构是这样的C# WPF中页视图模型的依赖项注入,c#,wpf,mvvm,dependency-injection,.net-core-3.1,C#,Wpf,Mvvm,Dependency Injection,.net Core 3.1,我正在使用.NETCore3.1创建一个WPF应用程序 我过去开发过ASP.Net应用程序,我很高兴能在WPF中使用它。我做了一些搜索,发现WPF中的DI不像ASP.Net中的DI那么简单,这意味着您必须注册视图和视图模型 我的结构是这样的 MainWindow |---BalanceIntegrationPage |---BalanceIntegrationViewModel 一切都在XAML中处理,MainWindow.XAML.cs只生成代码,BalanceIntegrationP
MainWindow
|---BalanceIntegrationPage
|---BalanceIntegrationViewModel
一切都在XAML中处理,MainWindow.XAML.cs只生成代码,BalanceIntegrationPage.XAML.cs在构造函数中添加了一行代码
DataContext = new ScaleIntegrationViewModel();
无法在xaml中处理,因为DI需要构造函数中的参数
这是我的app.xaml.cs:
protected override async void OnStartup(StartupEventArgs startupEventArgs)
{
base.OnStartup(startupEventArgs);
ServiceCollection services = new ServiceCollection();
services.AddScoped<MainWindow>();
services.AddScoped<ScaleInterfacePage>();
services.AddScoped<ScaleIntegrationViewModel>();
services.AddScoped<IScale>(provider => new Scale("1234"));
ServiceProvider serviceProvider = services.BuildServiceProvider();
MainWindow mainWindow = serviceProvider.GetService<MainWindow>();
mainWindow.Show();
}
我还尝试使用所描述的模式
当我单步执行代码时,ViewModel构造函数中的IScale对象始终为null
有什么建议吗
编辑:
根据注释,我删除了页面构造函数中的ViewModel调用,而是在.xaml中分配了它
这迫使我创建一个默认的无参数构造函数,然后它会破坏DI
我几乎开始觉得我需要将服务注入主窗口,然后将它们传递给我从那里调用的所有东西。这对我来说毫无意义,因为在这一点上,我可能会扔掉DI,在需要的时候重新创建它们。依赖注入意味着注入依赖项,但不要自己构建它们 在您的示例中,您可以在页面内部手动构造viewmodel。这不是DI。您必须将viewmodel的实例注入页面 您没有向我们展示如何将页面注入主窗口。我不确定使用DI将页面注入窗口是否是一个好的决定。这是UI,您可以使用数据模板和纯XAML来描述没有DI的一切 无论如何,要将viewmodel注入页面,只需在页面中引入构造函数参数:
public ScaleInterfacePage(ScaleIntegrationViewModel vm)
{
InitializeComponent();
DataContext = vm;
}
就这样,一切就绪。依赖项注入意味着注入依赖项,但不要自己构造它们 在您的示例中,您可以在页面内部手动构造viewmodel。这不是DI。您必须将viewmodel的实例注入页面 您没有向我们展示如何将页面注入主窗口。我不确定使用DI将页面注入窗口是否是一个好的决定。这是UI,您可以使用数据模板和纯XAML来描述没有DI的一切 无论如何,要将viewmodel注入页面,只需在页面中引入构造函数参数:
public ScaleInterfacePage(ScaleIntegrationViewModel vm)
{
InitializeComponent();
DataContext = vm;
}
就这样,您已经准备好了。您缺少某些依赖项的配置。从您发布的代码中,您没有配置IJMDataIntegration和iBlanceIntegrationContext: 为了实现依赖注入的全部功能并使模拟更容易,您应该在整个应用程序中使用依赖反转。这意味着您应该只依赖于接口,因此在构造函数中只有接口类型:
partial class MainWindow : Window
{
public MainWindow(IScaleIntegrationViewModel viewModel)
{
this.DataContext = viewModel;
}
}
像页面这样的控件应该通过DataTemplate生成,而不是直接在XAML中实例化。您所需要做的就是将页面视图模型注入到另一个视图模型中。将它们绑定到ContentPresenter,并定义一个针对页面视图模型类型的隐式数据模板。此模板包含实际页面。看这个
如果需要更多详细信息,请搜索“视图模型优先”模式。基本上,视图可以定义为数据模板并与视图模型类型关联。数据模板可以定义为资源,也可以在显示视图模型的控件中内联定义。控件的内容是视图模型实例,数据模板用于直观地表示它。这种技术是一种情况的示例,在这种情况下,首先实例化视图模型,然后创建视图。
这是首选方法,尤其是与依赖项注入结合使用。您缺少某些依赖项的配置。从您发布的代码中,您没有配置IJMDataIntegration和iBlanceIntegrationContext: 为了实现依赖注入的全部功能并使模拟更容易,您应该在整个应用程序中使用依赖反转。这意味着您应该只依赖于接口,因此在构造函数中只有接口类型:
partial class MainWindow : Window
{
public MainWindow(IScaleIntegrationViewModel viewModel)
{
this.DataContext = viewModel;
}
}
像页面这样的控件应该通过DataTemplate生成,而不是直接在XAML中实例化。您所需要做的就是将页面视图模型注入到另一个视图模型中。将它们绑定到ContentPresenter,并定义一个针对页面视图模型类型的隐式数据模板。此模板包含实际页面。看这个
如果需要更多详细信息,请搜索“视图模型优先”模式。基本上,视图可以定义为数据模板并与视图模型类型关联。可以定义数据模板
作为资源,也可以在显示视图模型的控件内内联定义。控件的内容是视图模型实例,数据模板用于直观地表示它。这种技术是一种情况的示例,在这种情况下,首先实例化视图模型,然后创建视图。
这是首选方法,尤其是与依赖项注入结合使用。手动实例化viewmodel,并且不为构造函数参数提供任何值,因此使用默认的空值。你到底不清楚什么?@dymanoid那么我该如何设置它来使用DI呢?我根据你的评论编辑了这个问题。有什么建议吗?您真的应该使用MVVM框架,大多数框架都内置了DI。@MXM依赖项注入是.NET Core 3.1的一项功能,因此这应该可以在本机上完成。如果我想使用框架或其他东西,我会回到使用UnityContainers并以这种方式进行DI,就像我在完整框架应用程序中所做的那样。目标是在这个项目中使用本机DI。谢谢你!这意味着您必须注册视图和视图模型——这取决于您使用的框架,以及您是否依赖于约定的依赖关系映射,而不是显式定义它。依赖约定方法只是意味着魔术在后台发生。您可以手动实例化viewmodel,并且不为构造函数参数提供任何值,因此使用默认的null值。你到底不清楚什么?@dymanoid那么我该如何设置它来使用DI呢?我根据你的评论编辑了这个问题。有什么建议吗?您真的应该使用MVVM框架,大多数框架都内置了DI。@MXM依赖项注入是.NET Core 3.1的一项功能,因此这应该可以在本机上完成。如果我想使用框架或其他东西,我会回到使用UnityContainers并以这种方式进行DI,就像我在完整框架应用程序中所做的那样。目标是在这个项目中使用本机DI。谢谢你!这意味着您必须注册视图和视图模型——这取决于您使用的框架,以及您是否依赖于约定的依赖关系映射,而不是显式定义它。依赖约定方法只是意味着神奇发生在后台。我的页面不会被注入到窗口中。它是在XAML中声明的,带有一个标记“```如果我删除无参数页面构造函数,它将停止加载。我想我的脱节就在这里。在ASP.Net中,我注册的任何服务似乎都可以注入构造函数。我想在WPF中似乎不是这样的?似乎需要一个复杂的依赖链,我调用主窗口,然后将页面注入其中,然后将viewmodel注入其中,依此类推。@JoeK,不,DI不是这样工作的-不需要将依赖项从上向下转发。由于您没有显示整个设置,我无法指出您的问题所在。@dyamanoid我不知道整个设置是什么意思?你有什么问题我在回复中没有回答吗?我的页面没有被注入窗口。它是在XAML中声明的,带有一个标记“```如果我删除无参数页面构造函数,它将停止加载。我想我的脱节就在这里。在ASP.Net中,我注册的任何服务似乎都可以注入构造函数。我想在WPF中似乎不是这样的?似乎需要一个复杂的依赖链,我调用主窗口,然后将页面注入其中,然后将viewmodel注入其中,依此类推。@JoeK,不,DI不是这样工作的-不需要将依赖项从上向下转发。由于您没有显示整个设置,我无法指出您的问题所在。@dyamanoid我不知道整个设置是什么意思?你有什么问题我在回答中没有提到吗?这有助于让你更有意义,至少比其他人更有意义,谢谢!我没有错过DataContext的配置,它们的设置方式与IScale接口完全相同,我只是在处理scale部分时将它们注释掉了。我想现在我只需要给viewmodels留下可选参数,这样我就可以在测试时模拟我需要的接口。我使用DI的主要原因是为了使测试更容易一些。这样我就不必改变视图的整个范例。再次感谢!这有助于使更多的意义,至少比其他人,谢谢!我没有错过DataContext的配置,它们的设置方式与IScale接口完全相同,我只是在处理scale部分时将它们注释掉了。我想现在我只需要给viewmodels留下可选参数,这样我就可以在测试时模拟我需要的接口。Th 我使用DI的主要原因是为了使测试更容易一些。这样我就不必改变视图的整个范例。再次感谢!
partial class MainWindow : Window
{
public MainWindow(IScaleIntegrationViewModel viewModel)
{
this.DataContext = viewModel;
}
}