我的应用程序有一个菜单选项,允许创建一个新帐户。菜单选项的命令绑定到我的ViewModel中的命令(NewAccountCommand)。当用户单击创建新帐户的选项时,应用程序将显示“新帐户”对话框,用户可以在其中输入名称,地址等数据...然后单击“确定”关闭对话框并创建新帐户。
我知道ViewModel中的代码不正确,因为它创建了“新帐户”对话框并调用了ShowDialog()。以下是VM的片段:
var modelResult = newAccountDialog.ShowDialog();
if (modelResult == true)
{
//Create the new account
}
如何避免在我的VM中创建和显示对话框,以便我可以对VM进行单元测试?
答案 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的一些解耦。