Joe*_*e K 6 c# wpf dependency-injection mvvm .net-core-3.1
我正在使用 .NET core 3.1 创建一个 WPF 应用程序,我过去开发过 ASP.Net 应用程序,我很高兴在 WPF 中使用它。我做了一些搜索,发现 WPF 中的 DI 并不像 ASP.Net 中那样简单,这意味着您必须注册视图和视图模型。
我的结构是这样的
MainWindow
|---BalanceIntegrationPage
|---BalanceIntegrationViewModel
Run Code Online (Sandbox Code Playgroud)
一切都在 XAML 中处理,MainWindow.xaml.cs 仅生成代码,而 BalanceIntegrationPage.xaml.cs 在构造函数中添加了一行
DataContext = new ScaleIntegrationViewModel();
Run Code Online (Sandbox Code Playgroud)
这无法在 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();
}
Run Code Online (Sandbox Code Playgroud)
我的 ScaleIntegrationViewModel 看起来像:
public ScaleIntegrationViewModel(IJMDataIntegration jmContext = null, IBalanceIntegrationContext localContext = null, IScale scale = null)
{
_jmContext = jmContext ?? new JMDataIntegration();
_localContext = localContext ?? new BalanceIntegrationContext();
_scale = scale ?? new Scale("1234");
//JK read from config
_commPort = "1234";
}
Run Code Online (Sandbox Code Playgroud)
我还尝试使用此处描述的模式
当我单步执行代码时,ViewModel 构造函数中的 IScale 对象始终为 null。
有什么建议么??
编辑:
根据评论,我删除了页面构造函数中的 ViewModel 调用,而是将其分配到 .xaml 上,这迫使我创建一个默认的无参数构造函数,该构造函数随后会破坏 DI。
几乎开始看起来我需要将服务注入到 MainWindow ctor 中,然后将它们传递给我从那里调用的所有内容。这对我来说毫无意义,因为到那时,我可能会扔掉 DI,并在需要时重新安装它们。
您缺少某些依赖项的配置。从您发布的代码中,您错过了配置IJMDataIntegration
和IBalanceIntegrationContext
:
protected override async void OnStartup(StartupEventArgs startupEventArgs)
{
base.OnStartup(startupEventArgs);
ServiceCollection services = new ServiceCollection();
services.AddScoped<MainWindow>();
services.AddScoped<ScaleInterfacePage>();
services.AddScoped<IJMDataIntegration, JMDataIntegration>();
services.AddScoped<IBalanceIntegrationContext, BalanceIntegrationContext>();
services.AddScoped<IScale>(provider => new Scale("1234"));
services.AddScoped<ScaleIntegrationViewModel>();
ServiceProvider serviceProvider = services.BuildServiceProvider();
MainWindow mainWindow = serviceProvider.GetService<MainWindow>();
mainWindow.Show();
}
Run Code Online (Sandbox Code Playgroud)
另外,正如已经提到的,您还必须将视图模型注入到中MainWindow
。这是依赖关系图开始的地方,即应用程序的根:
partial class MainWindow : Window
{
public MainWindow(ScaleIntegrationViewModel viewModel)
{
this.DataContext = viewModel;
}
}
Run Code Online (Sandbox Code Playgroud)
为了启用依赖注入的全部功能(并使模拟更容易),您应该在整个应用程序中使用依赖反转。这意味着您应该只依赖于接口,因此构造函数中只具有接口类型:
partial class MainWindow : Window
{
public MainWindow(IScaleIntegrationViewModel viewModel)
{
this.DataContext = viewModel;
}
}
Run Code Online (Sandbox Code Playgroud)
像页面这样的控件应该通过 XAML 生成DataTemplate
,而不是直接在 XAML 中实例化。您需要做的就是将页面视图模型注入到另一个视图模型中。将它们绑定到 aContentPresenter
并定义一个DataTemplate
以页面视图模型类型为目标的隐式。该模板包含实际页面。请参阅此示例。
如果您需要更多详细信息,请搜索视图模型优先模式。基本上,视图可以定义为数据模板并与视图模型类型相关联。数据模板可以定义为资源,也可以在将显示视图模型的控件内内嵌定义。控件的内容是视图模型实例,数据模板用于直观地表示它。该技术是首先实例化视图模型,然后创建视图的情况的示例。
这是首选方式,尤其是与依赖注入结合使用时。
归档时间: |
|
查看次数: |
11034 次 |
最近记录: |