0

I have my MainView and an associated MainViewViewModel which are linked by ViewModelLocator.

Within MainViewViewModel there is a command which should trigger a new Window to open which has it's own View and ViewModel (NewView and NewViewViewModel).

In a lot of the examples I've seen it is suggested to use Mvvmlight's Messenger to do something like this:

public class MainViewViewModel
{

    private void OpenNewWindow()
    {
        Messenger.Default.Send(new NotificationMessage("NewView"));
    }

}

And then register the NewViewViewModel and handle the message like this:

public class NewViewViewModel
{
   public NewViewViewModel()
   {
       Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
   }

    private void NotificationMessageReceived(NotificationMessage obj)
    {
         if (obj.Notification == "NewView")
         {
             NewView view = new NewView();
             view.Show();
         }
    }
}

However, this doesn't work because the NewViewViewModel isn't yet instantiated (so isn't registered with Messenger). Additionally, this doesn't fit with MVVM because NewViewViewModel is responsible for creating NewView.

What is the correct way to achieve a simple command which instantiates and opens a new View and ViewModel pair which are linked via ViewModelLocator and setting of DataContext="{Binding NewView, Source={StaticResource Locator}}" in NewView.xml?

WSC
  • 903
  • 10
  • 30
  • Why is viewmodellocator part of the answer? Reason I ask is there are other options. For example why not send the viewmodel instance and type of view in a message? Subscribe in mainwindow. In mainwindow you could instantiate the window. set datacontext to the viewmodel and show the window. – Andy Feb 21 '20 at 15:16
  • "In mainwindow you could instantiate the window." - This is what I'm learning towards as every other solution seems overly complicated, however this doesn't follow the MVVM architecture because a ViewModel is responsible for creating Views. – WSC Feb 21 '20 at 15:29
  • The code in mainwindow would be creating the view. But.... The whole idea of the pattern is to make things easier. It's not an end to itself. So I wouldn't worry too much about whether this breaks any abstract architectural pattern. BTW. I recommended passing an instance of a viewmodel because that then allows you to resolve any dependencies or pass in parameters or whatever you like from the "calling "viewmodel. – Andy Feb 21 '20 at 15:43

1 Answers1

3

Use a window service:

MVVM show new window from VM when seperated projects

You may either inject the view model to with an IWindowService implementation or use a static WindowService class:

public static class WindowService
{
    public static void OpenWindow()
    {
        NewView view = new NewView();
        view.Show();
    }
}

Dependency injection is obviously preferable for being able to unit test the view model(s) and switch implementations of IWindowService at runtime.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • I must be missing something, but to what namespace does IWindowService belong? I can't find it. – WSC Feb 21 '20 at 14:34
  • You need to define it yourself. Follow the link in my answer... – mm8 Feb 21 '20 at 14:35
  • I did read that but all I see is WindowService implemented like this: `public class WindowService : IWindowService` where is IWindowService defined? – WSC Feb 21 '20 at 14:38
  • @WSC: It's just an interface that you need to define: `public interface IWindowService { void OpenProfileWindow(AddProfileViewModel vm); }` – mm8 Feb 21 '20 at 14:40