ViewModels开启对话

时间:2012-05-24 19:23:44

标签: c# mvvm

ViewModel打开附加对话有什么问题吗?假设我有一个MainView和一个MainViewModel。 MainViewModel是MainView的datacontext,实际上并不知道或者对主视图本身有任何依赖。

但是,有时主视图需要打开会影响ViewModel数据的对话框。例如,我可能想要显示对话并显示一些项目以允许用户进行选择。所以,我已经解决了这个问题:

在我的ViewModel中,我有以下方法:AddItemEditItemDeleteItem。但是,为了提供要添加或编辑的项目,我需要在一些对话框中显示一个列表供用户选择。现在我让ViewModel这样做只是因为我不想为这些简单的任务实现额外的抽象级别。让ViewModel执行此操作意味着它可以提供要显示给用户的列表,并且当用户完成编辑或选择时,它可以轻松更新其成员集合/属性。

我是否应该接受这种方法的解决?

5 个答案:

答案 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方法的必要数据。我希望这会有所帮助:)