5

I've read about it in a bunch of places. Most of the people are referring to these two links:

I don't understand either of them. I am a beginner when it comes to MVVM. Some people are mentioning controllers when it comes to window manipulation in MVVM. What are those and how are they implemented? By book, MVVM is consisted of model, viewmodel and view - where do controllers come in?

If someone could provide a sample of the following use case, that would be terrific (for all those people who are just getting started with this, as I am):

  1. Prerequisite: A window is opened.
  2. User clicks a button.
  3. New window is opened and some data is passed to that window, i.e. some string.
  4. New window is closed (or a button is clicked) and some data is passed to the first window.
  5. Passed data has changed something on the window.
Community
  • 1
  • 1
Boris
  • 9,986
  • 34
  • 110
  • 147

2 Answers2

0

The ViewModel to ViewModel communication is usually handled by an implementation of the Event Aggregator pattern.

MVVM Light uses the Messenger class, Prism has another implementation but basically that is one way to send messages between View Models without coupling.

There are some examples, and Articles describing the usage. I would suggest taking a look at it.

Regarding the controllers stuff in WPF, I don't know.

Regarding the example:

-I Have a Windows with its WindowsViewModel. This class should have a Command bound to the Button.

-The user clicks the button. Executes the command.

-The Command opens a new Window.

Here you should create the Dialog View Model and somehow you should create the Window. Or create the Window with a ViewModel, but ViewModel shouldn't know much about the View otherwise is not testable.

We use something like this because we have some requirements, but it could be much much simplier, it happens it's the only example I have at hand:

bool? ShowDialogImpl<TViewModel>(Action<TViewModel> setup) where TViewModel : ViewModel
{
    return (bool?)DispatcherHelper.UIDispatcher.Invoke(
        (Func<bool?>)(() =>
        {
            var viewModel = viewModelFactory.Get<TViewModel>();
            viewModel.ViewService = this;
            setup(viewModel);
            var window = new Window
            {
                Owner = this,
                SizeToContent = SizeToContent.WidthAndHeight,
                WindowStartupLocation = WindowStartupLocation.CenterOwner,
                Content = ViewFactory.CreateView<TViewModel>(),
                DataContext = viewModel,
                WindowStyle = WindowStyle.ToolWindow,
                ShowInTaskbar = false
            };
            window.SetBinding(TitleProperty, new Binding("Title"));
            openDialogs.Push(window);
            window.Activated += (sender, args) => window.SizeToContent = SizeToContent.Manual;
            var result = window.ShowDialog();
            openDialogs.Pop();
            viewModelFactory.Release(viewModel);
            return result;
        }));
}

Basically: We create a window and with a view model. The view model is created from a factory using an container. The setup Action delegate is the entry point for our data.

  • Communication:

The first Windows is a Grid, and the second Dialog to edit data of the grid. Inf the Windows we have:

messenger.Register<EntityUpdated<FooClass>>(this, message => UpdateItem(message.Entity));

And in the Dialog:

messenger.Send(new EntityUpdated<FooClass>(subject));

This way, we know when something was updated in the Edit Dialog in order to refresh the grid.

Hope this help you :)

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Marcote
  • 2,977
  • 1
  • 25
  • 24
  • Thanks for the reply. I don't understand the Event Aggregator pattern (yet), so I think I need to focus on that in order to understand your example. Please tell me, in your application, when the user clicks a button that is supposed to open a new window, how did you manage that? Do you call a command that is added to the ViewModel and then it fires some events? Thanks. – Boris Apr 08 '11 at 16:01
  • Yep. We use commands as much as possible. The method bound to the command is the responsible for the call: AddCommand = new RelayCommand(Add); where Add : void Add() { ViewService.ShowDialog(); } The Event Aggregator is like a middle man that decouples the subscriber of the event from the publisher. This way you can do eventing without both parts (subscribers and publisher) know each other. – Marcote Apr 08 '11 at 16:10
  • MVVM Light is a delight! I've figured it all out and it works well. Thanks Markust for helping me out. – Boris Apr 12 '11 at 09:40
  • 1
    Directly opening a window from the ViewModel seems like it breaks the MVVM ideology. If you do that, you can no longer simply Unit Test your view model. I think you'd want something like an IWindowManager that you can mock for Unit Tests, but provide concrete window opening/closing for the application in non-test mode. – Mike Caron Jul 10 '13 at 14:57
  • It's a Dialog, but I agree. – Marcote Jul 10 '13 at 20:01
0

If you aren't planning on allowing the user to switch back and forth between the windows, while both are open (i.e., the first opens the second, and the second must be closed to return to the first), you could simply set the viewmodel for both windows to the same viewmodel instance, and open the 2nd window as modal, and the strings you are passing back and forth, would simply be properties of the view model, with data bindings to something in the view.

xdumaine
  • 10,096
  • 6
  • 62
  • 103
  • Unfortunately, my application will include windows that are not modal. Also, I intend to have one ViewModel per View. Thanks for sharing your thoughts on the subject though. – Boris Apr 08 '11 at 15:56