大家好,提前感谢您的宝贵时间。
我目前正在为我正在编写的一个小型商务应用程序使用 WPF 学习 MVVM。我读了很多关于 MVVM 模式的文章,发现其中一个关键领域是尽可能将 ViewModel 与 View 解耦。
我想在我的应用程序中打开一个新窗口,但我不确定是否应该使用 ICommand 从 ViewModel 打开它,或者使用标准事件直接从视图打开它。与我一起工作的人建议我应该使用命令,但后来我认为这意味着在我的 ViewModel 中引用视图,根据我的理解,这正是 MVVM 模式重点避免的。
我的理解是,如果打开一个窗口仅用于导航目的,并且打开新窗口的过程对模型没有影响,那么我应该使用标准事件将所有这些保留在视图上。
我知道在软件开发中一切都“取决于”,但我猜我的问题是否有一个“正确”/标准的方法来做到这一点?
最诚挚的问候, 丹尼尔
是的,虚拟机应该利用视图可以订阅的事件与视图进行通信...
在虚拟机中:
public event EventHandler<NotificationEventArgs<string>> DisplayOptionsNotice;
视图中:
private readonly MainViewModel mvm;
...
mvm = DataContext as MainViewModel;
mvm.DisplayOptionsNotice += DisplayOptionsWindow;
...
private void DisplayOptionsWindow(object sender, NotificationEventArgs<string> e)
{
...
optionsWindow = new OptionsWindow { Owner = this };
optionsWindow.ShowDialog();
...
}
但后来我认为这意味着在我的 ViewModel 中引用 View,根据我的理解,这正是 MVVM 模式重点要避免的。
一般来说,处理这种情况的方式是通过某种形式的控制反转。大多数 MVVM 框架将提供某种形式的服务来打开窗口,并使用服务定位器或依赖注入向 ViewModel 提供服务。
这允许您的 ViewModel 与特定视图渲染框架保持分离 - 您可以将服务传递给新 VM 并说“在窗口中显示此 VM”,并且该代码将是特定于平台的。
正如 Reed 所说,服务定位器或 DI 将完成这项工作,并且不会破坏 MVVM 模式。
根据我的经验,你必须做三件事:
首先检查服务定位器或 Di 看看什么对您更友好并实施它。
第二步开始制作您的视图(windows\ Messagebox - 如果您愿意)将实现的 IWindow\IWindowDialog 界面。
最后一件事是实现windows\消息。
从头开始需要时间(我做到了),但如果你一次专注于一件事。 你把时间减少了一半。
祝你好运
如果您选择从 ViewModel 层创建新窗口,您可以这样做:
public interface IWindow<TViewModel>{}
public partial class MyWindow : IWindow<MyWindowViewModel>
public void Show(object viewModel)
{
var types = Assembly.GetExecutingAssembly().GetTypes().ToList();
foreach (var view in types)
{
var @interface = view.GetInterface(typeof(IWindow<>).Name);
if (@interface == null)
continue;
if (@interface.GenericTypeArguments.FirstOrDefault() != viewModel.GetType())
continue;
var windowObject = Activator.CreateInstance(view);
if (windowObject is not Window window)
continue;
window.DataContext = viewModel;
window.Show();
}
}