ViewModel打开附加对话有什么问题吗?假设我有一个MainView和一个MainViewModel。 MainViewModel是MainView的datacontext,实际上并不知道或者对主视图本身有任何依赖。
但是,有时主视图需要打开会影响ViewModel数据的对话框。例如,我可能想要显示对话并显示一些项目以允许用户进行选择。所以,我已经解决了这个问题:
在我的ViewModel中,我有以下方法:AddItem
,EditItem
和DeleteItem
。但是,为了提供要添加或编辑的项目,我需要在一些对话框中显示一个列表供用户选择。现在我让ViewModel这样做只是因为我不想为这些简单的任务实现额外的抽象级别。让ViewModel执行此操作意味着它可以提供要显示给用户的列表,并且当用户完成编辑或选择时,它可以轻松更新其成员集合/属性。
我是否应该接受这种方法的解决?
答案 0 :(得分:4)
拍摄?不。但是有充分的理由不这样做。
首先,它会杀死ViewModel的可测试性,因为现在有一个可视化组件。当您尝试针对它编写自动单元测试时,您仍然需要与它进行交互。你可以嘲笑它,但是当你调用UI方法时,这样做会变得更加困难。
其次,您的viewmodel不应该关心显示的内容。当你开始组合这些东西时,会有一个真正的“分离关注”问题。
第三,它只是一个“代码味道。”
您可以采取一些措施来规避此问题。我建议的第一件事是不要使用对话框。对话有其自己的位置,但程序员往往过度使用它们。重新思考您的设计,并尝试弄清楚如何在不中断用户的情况下完成工作。
其次,考虑使用消息传递框架在viewmodel和view之间发送消息以导航到对话框(如果你绝对 使用它们)。消息很容易模拟和/或编写单元测试。
答案 1 :(得分:1)
简单的方法:使用对话服务 - 易于使用,易于单元测试!
请参阅this。
答案 2 :(得分:0)
我认为ViewModels彼此之间没有任何问题。问题是他们是否开始访问视图或其他对话框,因为这会影响系统的可测试性。
如果你真的想要一个更松散耦合的系统,你可以使用某种消息系统进行通信,但我怀疑你需要这个: - )
答案 3 :(得分:0)
我总是使用Seelctor服务(只是一个基本的对话服务)来做到这一点 - 它是可测试的和可模拟的,并且保持代码非常稳固。
class ViewModel
{
public ICommand ShowListSelectorForCounterparties { get; set; }
public IListSelectorService ListSelector { get; set; }
public void OnExecuteShowCounterpartySelector()
{
this.Counterparty = this.ListSelector.Select<Counterparty>();
}
}
IListSelectorService可以在运行时实例化对话框,显示列表并返回所选项目。以这种方式运行它的主要好处是你的单元测试可以模拟IListSelectorService。
答案 4 :(得分:0)
我不确定您是否仍在寻找任何帮助,但我在对话框中采用的方法是让视图模型引发视图可以处理的事件。现在,视图可以执行任何将数据提供给视图模型的操作,因此您可以在视图中显示对话框而不会出现问题。您将对话框中的响应传递给事件的EventArgs,以便视图模型具有正在查找的数据以便继续。
例如:
Public Class View
Private WithEvents _VM AS new ViewModel()
Private Sub _VM_AddingItem(Sender AS Object, E AS ViewModel.ItemEventArgs)
Dim Dialog As new SomeDialog()
If Dialog.ShowDialog then
E.Item = Dialog.Item
Else
E.Cancel = True
End If
End Sub
End Class
Public Class ViewModel
Public Sub AddItem(Item AS Object)
Do Some Work here
End Sub
Private Sub _AddItem()
Dim Args AS New ItemEventArgs()
OnAddingItem(Args)
If not Args.Cancel Then AddItem(Args.Item)
End Sub
Protected Sub OnAddingItem()
RaiseEvent AddingItem(me, ItemEventArgs)
End Sub
Public Event AddingItem(Sender AS Object, E As ItemEventArgs)
Public Class ItemEventArgs
Public Property Item AS Object
Public Property Cancel AS Boolean = false
End Class
End Class
然后只需将命令连接到私有_AddItem
方法,该方法只会引发事件以收集AddItem
方法的必要数据。我希望这会有所帮助:)