Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF中页视图模型的依赖项注入_C#_Wpf_Mvvm_Dependency Injection_.net Core 3.1 - Fatal编程技术网

C# WPF中页视图模型的依赖项注入

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

我正在使用.NETCore3.1创建一个WPF应用程序 我过去开发过ASP.Net应用程序,我很高兴能在WPF中使用它。我做了一些搜索,发现WPF中的DI不像ASP.Net中的DI那么简单,这意味着您必须注册视图和视图模型

我的结构是这样的

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;
  }
}