tags:

views:

63

answers:

2

I am somewhat new to MVVM. I am not sure what the best way is to do what I am trying to do.

Here is the scenario:

I have a VM that is going to show another window. I can call myNewWindowView.Show(), but first I need to set some data in the VM of my new window.

Should I expose both the myNewWindowView and the NewWindowViewModel to the calling ViewModel?

Here is an example:

class MainVM
{
    public void FindCustomer(string nameParial)
    {
       List<Customer> customers = ServiceCall.GetCustomers(nameParital);
       // This is the part I am not sure how to do.  I am not sure if this
       //  View Model should have a reference to a different view model and
       //  the view too.
       myNewWindowViewModel.CustomerList = customers;
       myNewWindowView.Show();
    }
}
+1  A: 

I would keep the viewmodel separate from any view. I tend to think of them as layers, but they are only interchangeable in one direction.

So a model of type foo can have any view model layered on top of it, and it never expects or cares about the viewmodel type.

A viewmodel can only be for one type of model, but it doesn't care or expect what type of view will use it.

A view will be for a particular type of viewmodel.

What you seem to have is a viewmodel the cares about what views are doing, which seems wrong to me.

If it were me, I'd get the view for the MainVM to display the new window, getting the MainVM to pass out the appropriate viewmodel for the new window.

This is the code I would put behind the view for the main viewmodel

class MainWindow : Window
{
     public MainWindow()
     {
          Initialize();
          DataContext = new MainVM();
     }

     public void FindCustomerClick(object sender, RoutedEventArgs args)
     {
          CustomerListView clv = new CustomerListView();
          clv.DataContext = (DataContext as MainVM).FindCustomer(search.Text);
          clv.Show();
     }
}

As you can see, the viewmodel has a method that takes a string and returns a CustomerListViewModel, which is then applied to the DataContext of a CustomerListView.

Matt Ellen
Sounds good, but also sounds fuzzy. Can you show me an example of how you would do my example right? (Ie have one window open another with some data passed between them.)
Vaccano
I will try. I'll probably have to fix it up later, as I'm doing this from my phone :)
Matt Ellen
+2  A: 

Don't reference views inside your view model. Have views create views and view models create view models.

A simple way to accomplish this separation of concerns is with events. The quick and dirty way to do it is to create a ChildViewModel property on your parent view model, and then handle PropertyChanged in the view, e.g.:

ParentViewModel vm = (ParentViewModel)DataContext;
vm.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "ChildViewModel")
    {
        MyChildWindow w = new MyChildWindow();
        w.Show(vm.ChildViewModel);
    }
};

Now every time the parent view model changes the ChildViewModel property, the parent view will open a new child view.

A less quick, and less dirty, approach is to create a CreateViewEventHandler delegate and CreateViewEventArgs class, and make the event handler, and a protected OnCreateView method, part of your base view model class (assuming you have one). This allows the view model to be a lot more explicit about when a child window should be created.

Note that if it's important for the parent view model to know when the child view model has closed, the child view model can expose an event that the parent can subscribe to (or, again, use a property and the PropertyChanged event).

Note that in both cases, you can write unit tests that verify that the view model opens the window (i.e. raises the event) when it's supposed to without involving the views.

I haven't used any MVVM frameworks myself, but the ones I've looked at have messaging tools that are designed to facilitate this kind of thing.

Robert Rossney