Thursday, September 5, 2013

MVVM Light, WPF, and Opening New Windows

Ran across this while trying to figure out how to properly open a new window in a WPF project using MVVM Light toolkit.

Viv posts a good example project using Messenger to communicate between ViewModel and View. But the code used to new up the appropriate ViewModel and View for the new window is all in the code behind for MainWindow (MainWindow.xaml.cs). I generally avoid putting anything in a code behind, so I added another button showing how to do the same thing without the code behind.

Sample Project - Dropbox download page

Which method is better? Pro’s and Con’s? Let me know, I just dislike code behind.

Here are the main points, see the sample project for the details.
I'm utilizing the ViewModelLocator singleton for this static method

   1:      public static void CreateWindow(OpenWindowMessage message)
   2:      {
   3:          var uniqueKey = System.Guid.NewGuid().ToString();
   4:          var nonModalWindowVM = SimpleIoc.Default.GetInstance<NonModalWindowViewModel>(uniqueKey);
   5:          nonModalWindowVM.MyText = message.Argument;
   6:          var nonModalWindow = new NonModalWindow()
   7:          {
   8:              DataContext = nonModalWindowVM
   9:          };
  10:          nonModalWindow.Closed += (sender, args) => SimpleIoc.Default.Unregister(uniqueKey);
  11:          nonModalWindow.Show();
  12:      }


The MainWindowViewModel has a RelayCommand so the button on MainWindow.xaml has something to bind to.

public RelayCommand OpenNonModalDialog_NoCodeBehind { get; private set; }

Constructor wires up the RelayCommand

      OpenNonModalDialog =
        new RelayCommand(
          () =>
          Messenger.Default.Send<OpenWindowMessage>(
            new OpenWindowMessage() {Type = WindowType.kNonModal, Argument = SomeString}));
        
        //No Code Behind
      OpenNonModalDialog_NoCodeBehind =
        new RelayCommand(
          () =>
            ViewModelLocator.CreateWindow(new OpenWindowMessage() { Type = WindowType.kNonModal, Argument = SomeString }));

Notice the first is using Messenger to tell the code behind to create the window.

The No Code Behind is using the static method on ViewModelLocator.

MainWindow.xaml, Button.Command is bound to the no code behind relay command

    <Button Grid.Row="1"
        Grid.Column="0"
        Margin="10"
        Command="{Binding OpenNonModalDialog_NoCodeBehind}"
        Content="Open No Code Behind" />