【发布时间】:2023-03-27 15:43:01
【问题描述】:
我有一个简单的 WPF 应用程序,它利用 Unity 框架进行依赖注入。目前,我正在尝试简化我在 MVVM 模式实现中的视图之间导航的方法;但是,整个 Stack Overflow 中的许多示例都没有考虑依赖注入警告。
我有两个完全不同的观点。
一,Main 充当加载内容的主窗口(非常典型;消除了不必要的内容):
<Window x:Class="Application.UI.Main">
<Grid Background="White">
<ContentControl Content="{Binding aProperty}"/>
</Grid>
</Window>
构造函数通过构造函数注入接收 ViewModel(同样,非常简单):
public partial class Main
{
private MainViewModel _mainViewModel;
public Main (MainViewModel mainViewModel)
{
InitializeComponent();
this.DataContext = _mainViewModel = mainViewModel;
}
}
然后我有一个UserControl,Home,我想“导航”到主窗口(即设置ContentControl。它的构造函数也通过构造函数注入以相同的方式接收一个 ViewModel Main确实如此。同样简单:
public Home(HomeViewModel homeViewModel)
{
InitializeComponent();
// Set Data Context:
this.DataContext = homeViewModel;
}
这里的主要问题是,我想启用基于构造函数的注入,同时尽可能保持纯粹的 MVVM 实现。
我是MVVM的View-first阵营,关于它你可以找到一个很好的discussion in these comments。
我已经看到一些关于基于导航的服务的想法的典故;但是,我不确定这是否能保持 MVVM 所追求的关注点分离。 DataTemplates 需要不带参数的 View 构造函数,我读过对 DataTemplates 的批评,认为 ViewModels 不应参与 View 的实例化。
This solution(在我看来)是完全错误的,因为 ViewModel 意识到了它的 View 并依赖于 ViewModel 实例化的服务,这使得真正的依赖注入来解决 ViewModel 和 View 依赖几乎是不可能的。这个问题在这个MSDN article中使用RelayCommand很明显。
维护对Main 视图的全局、类似单例的引用的导航服务是否最有意义? Main 视图是否可以公开方法,例如:
public void SetContent(UserControl userControl) { //... }
然后由该服务访问?
【问题讨论】:
-
虽然您说您处于“视图优先阵营”,但您尝试解决的确切场景在 VM 优先方法中很容易处理。使用您的 DI 容器构建您的视图模型图,并让 DataTemplates 处理接线。
-
@AndrewHanlon 那是我在一秒钟前刚刚做出的改变(我仍在努力确定每一个的含义——我想我实际上是在 VM-first 阵营)。你能给我举个例子吗?
-
哦,等等。在这种情况下,除了 DataTemplate 之外,View 甚至都不知道 ViewModel,对吗?如果我使用 DI 解决依赖关系,
Main如何知道要显示哪个视图?即依赖项必须存在。使用像 Unity 这样的框架,我无法从 IoC 中获取内容(我也不想这样做) -
因此,在 VM-first 中,View 知道 VM(或 VM 合约接口),但没有直接注入 VM,只能通过 DataContext,它是通过 ContentControl 自动设置的.
-
查看Here的方法7/8。至于初始化,只需更改app.xml,这样您的主视图就不会自动创建。然后您可以执行所有 VM 初始化 (DI),然后创建 Main 并设置其 DataContext。在此之后,让 DataTemplates 为您完成接线。
标签: c# .net wpf mvvm dependency-injection