如何避免在我的ViewModel中查看特定代码

时间:2009-11-13 16:24:33

标签: mvvm

我的应用程序有一个菜单选项,允许创建一个新帐户。菜单选项的命令绑定到我的ViewModel中的命令(NewAccountCommand)。当用户单击创建新帐户的选项时,应用程序将显示“新帐户”对话框,用户可以在其中输入名称,地址等数据...然后单击“确定”关闭对话框并创建新帐户。

我知道ViewModel中的代码不正确,因为它创建了“新帐户”对话框并调用了ShowDialog()。以下是VM的片段:

 var modelResult = newAccountDialog.ShowDialog();
 if (modelResult == true)
 {
   //Create the new account             
 }

如何避免在我的VM中创建和显示对话框,以便我可以对VM进行单元测试?

4 个答案:

答案 0 :(得分:2)

我喜欢此代码项目文章中解释的方法: http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

它基本上创建了一个WPF Dialog控件,可以嵌入另一个窗口或usercontrol的可视树中。

然后使用样式触发器,只要对话框中有内容,就会打开对话框。

所以你在xaml所要做的就是这个(其中DialogViewModel是ViewModel中的一个属性):

<MyControls:Dialog Content = {Binding DialogViewModel}/>

在您的ViewModel中,您只需执行以下操作:

DialogViewModel = new MyDialogViewModel();

所以在单元测试中你所要做的就是:

MyViewModel model = new MyViewModel();
model.DialogViewModel = new MyDialogViewModel();
model.DialogViewModel.InputProperty = "Here's my input";
//Assert whatever you want...

我个人在我的ViewModel中创建了一个ICommand属性,用于设置DialogViewModel属性,以便用户可以按下按钮以打开对话框。

所以我的ViewModel从不调用它只是实例化一个属性的对话框。视图解释该视图并显示一个对话框。这背后的美妙之处在于,如果您决定更改视图并且可能不显示对话框,则ViewModel不必更改一位。它将所有用户交互代码推送到视图中。创建一个wpf控件允许我在需要时重新使用它...

有很多方法可以做到这一点,我觉得这对我有好处。 :)

答案 1 :(得分:1)

在这种情况下,我通常会使用事件。该模型可以举起一个事件来询问信息,任何人都可以回复它。视图将侦听事件并显示对话框。

public class MyModel
{
    public void DoSomething()
    {
        var e = new SomeQuestionEventArgs();
        OnSomeQuestion(e);
        if (e.Handled)
            mTheAnswer = e.TheAnswer;
    }
    private string mTheAnswer;
    public string TheAnswer
    {
        get { return mTheAnswer; }
    }
    public delegate void SomeQuestionHandler(object sender, SomeQuestionEventArgs e);
    public event SomeQuestionHandler SomeQuestion;
    protected virtual void OnSomeQuestion(SomeQuestionEventArgs e)
    {
        if (SomeQuestion == null) return;
        SomeQuestion(this, e);
    }
}
public class SomeQuestionEventArgs
    : EventArgs
{
    private bool mHandled = false;
    public bool Handled
    {
        get { return mHandled; }
        set { mHandled = value; }
    }
    private string mTheAnswer;
    public string TheAnswer
    {
        get { return mTheAnswer; }
        set { mTheAnswer = value; }
    }
}
public class MyView
{
    private MyModel mModel;
    public MyModel Model
    {
        get { return mModel; }
        set
        {
            if (mModel != null)
                mModel.SomeQuestion -= new MyModel.SomeQuestionHandler(mModel_SomeQuestion);
            mModel = value;
            if (mModel != null)
                mModel.SomeQuestion += new MyModel.SomeQuestionHandler(mModel_SomeQuestion);
        }
    }
    void mModel_SomeQuestion(object sender, SomeQuestionEventArgs e)
    {
        var dlg = new MyDlg();
        if (dlg.ShowDialog() != DialogResult.OK) return;
        e.Handled = true;
        e.TheAnswer = dlg.TheAnswer;
    }
}

答案 2 :(得分:1)

WPF Application Framework (WAF)显示了如何实现这一目标的具体示例。

ViewModel示例应用程序显示一个电子邮件客户端,您可以在其中打开“电子邮件帐户设置”对话框。它使用依赖注入(MEF),因此您仍然可以对ViewModel进行单元测试。

希望这有帮助。

JBE

答案 3 :(得分:0)

有不同的方法。一种常见的方法是使用某种形式的依赖注入来注入对话服务,并使用该服务。

这允许在运行时插入该服务的任何实现(即:不同的视图),并且确实为您提供了从ViewModel到View的一些解耦。