Opening a new window from the MainWindow

Apr 28, 2010 at 5:31 PM
Edited Apr 28, 2010 at 5:32 PM

Hi,

What is the best way to open a new window from the viewmodel?

current I have something such as:

    private static void ShowAboutView()
    {
      var aboutView = new AboutView();
      aboutView.Show();
    }

ShowAboutView is an action from a RelayCommand in the MainViewModel.

This works but does not sit well.  What alternatives are there to opening a new window / view?  I would also be interested in assigned the new view an owner / parent window.

Apr 28, 2010 at 5:55 PM

What I've done for this is create an interface for any child windows that includes a Show method and events for any buttons that can be clicked. Then I have an IoC container set up in my ViewModelLocator (Ninject in my case, but Unity should work) and I have the interface for the window in the constructor of the ViewModel that will be using it.

This set up allows me to ...

  1. Mock the window for unit tests.
  2. Keep the UI of the window separate from the ViewModel calling it.
  3. Control when the window is displayed and what I do when its closed from the ViewModel.

I've also considered setting up Commands as dependency properties on the Window that I could bind to from another view. This would completely remove the child window's functionality from the concern of the ViewModel. I haven't done this yet because this solution works for me, but it could the a possibility if you're dogmatic about MVVM.

Apr 28, 2010 at 9:43 PM
Edited Apr 28, 2010 at 9:43 PM

Thank you for the quick reply.

This is what I did and it seems to be working, please confirm if this matches-up with what you previously described.

1- Created this Interface

  public interface IChildView
  {
    void Show();
  }

2 - Put this in my AboutViewModel

  public class AboutViewModel : ViewModelBase, IChildView
  {
    public void Show()
    {
      var aboutView = new AboutView();
      aboutView.Show();
    }
  }

3- Put this in my ViewModelLocator constructor

Container.RegisterType<IChildView, AboutViewModel>();

4- Modified my MainViewModel constructor to be

public MainViewModel(IChildView aboutView)
    {}

5- I can now call aboutView.Show() in my MainViewModel and voila my second window shows.

Is this what you had in mind?

Once again, Thank you for the time and expertise.

Apr 28, 2010 at 11:31 PM

That's very close to what I'm doing.

The difference is that you implemented an interface on a ViewModel, but I put it directly on a ChildWindow. Since my child window isn't doing much other than presenting a message and allowing the user to select one of a few buttons, I didn't think it needed a view model. I don't have any example code at the moment, but I hope to work on an example application using this and several other features of MVVM Light soon.

One thing about your solution that you might want to do is choose a more specific name for your interface. What if you want to use another child window? You can't register IChildView to multiple concrete types. I would have created it as IAboutChildView.

Keep in mind that there's nothing wrong with your solution. Everyone has different ideas about what's right. If you're happy with where your code got you and you can test your logic sufficiently, then you're in good shape.

Apr 29, 2010 at 4:08 AM

Excellent. I now understand the differences.

One other question.  I noticed in my MainViewModel I now have two parameters:

public MainViewModel(IAboutView aboutView, IHelpView helpView)

Lets say I had 6 views, what can help cut down the number of parameters? or is the reasoning if you have 6 views on a page maybe I should look into making a user control to consolidate some of the views and then pass in the user control?


Apr 29, 2010 at 10:57 AM

With dependency injection you will find your constructors getting huge parameter lists. Some people don't like this, but my opinion is that this is just an indication that you're saving code elsewhere. I think this is a good thing overall.

I have heard some people on twitter talking about large parameter lists being a warning sign that you class might have too many responsibilities. Its perfectly okay to have multiple view model classes whose responsibility is providing data to different portions of the view. For instance, in my application we have a LookupsViewModel that handles all of the data that any drop down lists bind to.

Consolidating all of your windows into a single user control is certainly a good strategy. My rule of thumb for controls is that I only take the time to encapsulate if I find myself doing something the same way 3 times. However, these child windows are pretty simple so I think its okay to have a version for each button combination. We have one that just has an Okay button, an Okay/Cancel and a Yes/No/Cancel.

Its too bad the MessageBox in Silverlight only allows Okay and OkayCancel because that means we never use it in our app in order to have consistency between our pop up windows.

Glad to help!