将视图模型的单独项目"enforce" MVVM:如何打开对话框?



在遵守MVVM模式的同时打开对话框似乎是常见的问题之一(在这里和其他地方)。我知道有一些像MVVM light这样的框架可以解决这个问题,但我目前正在做一个非常小的个人项目,在这个项目中,我试图自己做大部分事情来达到学习的目的。

为了"强迫"自己注意引用,我决定从UI项目中提取视图模型,并将它们放入一个单独的程序集中。UI项目引用UI.ViewModels,但不能反过来引用。这导致我在打开(模式)对话框窗口时遇到问题。

许多人似乎在使用DialogService,它的作用类似于:

internal class DialogService : IDialogService
{
public bool? OpenDialog(ViewModelBase vm)
{
Window window = new Window();
window.Content = vm;
return window.ShowDialog();
}
}

可以通过使用CCD_ 2从视图模型类型推断出相应的窗口内容。

不过,在我的场景中,这不起作用,因为DialogService需要在UI项目中,但我必须从视图模型中调用它。当然,我可以滥用DI/IoC将IDialogService实现注入到我的视图模型中,但这不是我想要做的

有什么严格的方法可以让它发挥作用吗

作为替代方案,我在ViewModelBase:中添加了以下代码

public abstract class ViewModelBase : INotifyPropertyChanged
{
...
public event Action<ViewModelBase, Action<bool?>> Navigate;
protected virtual void OnNavigate(ViewModelBase vm, Action<bool?> callback)
{
Navigate?.Invoke(vm, callback);
}
}

显然,可能会有更多的过载、其他参数、EventArgs等等;我可能也应该把它放到一个界面中。但到目前为止,这只是一个"想法"。

创建视图实例时(通过解析或例如在NavigationService中,请参见下文),我可以让NavigationService订阅该事件并调用回调这是个有问题/坏主意吗?这有什么缺点到目前为止(没有进行太多测试),有一件事我不喜欢,那就是打开对话框后无法继续下一行,而是必须在回调代码中继续。这也使得通过读取代码来遵循程序流程变得更加困难。

非常感谢您的任何意见!这是一个非常有趣的话题,由于SO上这些问题的许多答案都很过时,我希望了解更多关于当前最佳实践的信息:)

在我的场景中,这不起作用,因为DialogService需要在UI项目中,但我必须从视图模型中调用它。

IDialogService接口应在视图模型项目中定义。视图模型只知道这个接口,您可以在单元测试中轻松地提供它的模拟实现,只需返回bool?,而无需实际创建对话框。

IDialogService的具体实现,即创建窗口的DialogService类,应该在UI项目中实现。

我当然可以滥用DI/IoC将IDialogService实现注入到我的视图模型中,但这不是我想做的。

这不是对depenedency注入模式的滥用。这是一种典型而正确的用法。我自己也用过,效果很好。

扩展视图模型基类以提供某种对话框功能的另一种解决方案对我来说似乎是混乱和错误的。我当然会坚持将IDialogService接口注入到所有实际需要对话框服务的视图模型中。这与向它们注入任何其他服务是一样的。

为什么将实现IDialogService的类注入视图模型会滥用IoC?我认为这是一个很好的方法。

不要想太多,分离视图和逻辑项目是个好主意,只要使用对你有用的东西就行了。

在我的上一个项目中,我使用了ReactiveUI框架中的交互类。它可以很好地与对话框和文件选择器配合使用。我认为它与您的备选方案非常相似,您可以查看代码和示例。

它使用的是反应式扩展,但你应该明白这个想法。

最新更新