English 中文(简体)
How to avoid View specific code in my ViewModel
原标题:
  • 时间:2009-11-13 16:24:33
  •  标签:
  • mvvm

My application has a menu option to allow the creation of a new account. The menu option s command is bound to a command (NewAccountCommand) in my ViewModel. When the user clicks the option to create a new account, the app displays a "New Account" dialog where the user can enter such data as Name, Address, etc... and then clicks "Ok" to close the dialog and create the new account.

I know my code in the ViewModel is not correct because it creates the "New Account" dialog and calls ShowDialog(). Here is a snippet from the VM:

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

how do i avoid creating and showing the dialog from within my VM so I can unit test the VM?

最佳回答

In scenarios like this, I typically use events. The model can raise an event to ask for information and anybody can respond to it. The view would listen for the event and display the dialog.

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;
    }
}
问题回答

I like the approach explained in this codeproject article: http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

It basically creates a WPF Dialog control that can be embedded in the visual tree of another window or usercontrol.

It then uses a style trigger that causes the dialog to open up whenever there is content in the dialog.

so in you xaml all you have to do is this(where DialogViewModel is a property in you ViewModel):

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

and in you ViewModel you just have to do the following:

DialogViewModel = new MyDialogViewModel();

so in unit testing all you have to do is:

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

I personally create a ICommand property in my ViewModel that sets the DialogViewModel property, so that the user can push a button to get the dialog to open up.

So my ViewModel never calls a dialog it just instantiates a property. The view interprets that and display a dialog box. The beauty behind this is that if you decide to change your view at all and maybe not display a dialog, your ViewModel does not have to change one bit. It pushes all the User interaction code where it should be...in the view. And creating a wpf control allows me to re-use it whenever I need to...

There are many ways to do this, this is one I found to be good for me. :)

The WPF Application Framework (WAF) shows a concrete example how to accomplish this.

The ViewModel sample application shows an Email Client in which you can open the “Email Account Settings” dialog. It uses dependency injection (MEF) and so you are still able to unit test the ViewModel.

Hope this helps.

jbe

There are different approaches to this. One common approach is to use some form of dependency injection to inject a dialog service, and use the service.

This allows any implementation of that service (ie: a different view) to be plugged in at runtime, and does give you some decoupling from the ViewModel to View.





相关问题
Reactive Extensions (Rx) + MVVM =?

One of the main examples being used to explain the power of Reactive Extensions (Rx) is combining existing mouse events into a new event representing deltas during mouse drag: var mouseMoves = from ...

Where should the data be stored in MVVM?

I ve got this Silverlight Prism application that is using MVVM. The model calls a WCF service and a list of data is returned. The ViewModel is bound to the View, so the ViewModel should have a List ...

Where to put the calls to WCF or other webservices in MVVM?

I m building Silverlight applicaitions using Prism and MVVM. When calling WCF services on your own server, or even external webservices like the Bing api, would this be done from the Model? or from ...

How to avoid View specific code in my ViewModel

My application has a menu option to allow the creation of a new account. The menu option s command is bound to a command (NewAccountCommand) in my ViewModel. When the user clicks the option to create ...

WPF MVVM User Control binding issues

I have an application that uses MVVM. I have several items on the main window that bind to the ViewModel for that window. When I run it everything works. However, when I add a user control to the main ...

WPF: writing smoke tests using ViewModels

I am considering to write smoke tests for our WPF application. The question that I am faced is: should we use UI automation( or some other technology that creates a UI script), or is it good enough to ...

WPF - MVVM - NHibernate Validation

Im facing a bit of an issue when trying to validate a decimal property on domain object which is bound to a textbox on the view through the viewmodel. I am using NHibernate to decorate my property on ...

热门标签