Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM Light - Multiple ViewModels (and connecting them up)

Tags:

c#

.net

mvvm

wpf

views

I am trying to learn the MVVM pattern (C#), having come from a Windows Forms background. I am using the MVVM Light toolkit, and so far I think it is brilliant. I have made several small applications, however one thing I am struggling with is introducing a second view.

I want to (for example), have a button on my MainViewModel, which via a RelayCommand, opens up a new Window - let's say an "About" window. I have done hours of research on the web for this however it seems I can't get my AboutViewModel to communicate with/show my AboutView.

I have placed a receiving messenger in the code-behind constructor of the AboutView.xaml - however I can't get it to receive any messages from the AboutViewModel, and thus can't make it 'Show()'.

If anyone has an example of an Mvvm Light WPF app using multiple views that would be great :)

like image 971
Chris H Avatar asked Aug 21 '12 20:08

Chris H


People also ask

How do you communicate between two ViewModels?

We will add 3 buttons in ControlA and when the button is clicked from ControlA, we will put a message in ControlB. In Control B: Under ViewModel, add the class ControlBViewModel then add the code shown below. In the above class we can see that we have created a method called UpdateContent.

How do I share data between two ViewModels?

I decided to do it the traditional way: 1) define a thread-safe singleton 2) in Application_Startup, instantiate the singleton and all the ViewModels (at least the VM's that need to share info with each other), then save references to all the VM's in the Singleton. This way, any VM can access any other VM.

Can a ViewModel have multiple models?

ViewModel is nothing but a single class that may have multiple models. It contains multiple models as a property. It should not contain any method. In the above example, we have the required View model with two properties.

Can a view have multiple ViewModels WPF?

No that is fine; each object should be a ViewModel in its own right.


1 Answers

There are two ways I can think to do this easily

The first would be to use a Popup instead of a new Window. For example, I often put properties in my ViewModel for PopupContent and IsPopupVisible, and set those values anytime I want to display my Popup control. For example, a ShowAboutPopup relay command might run something like this:

void ShowAboutPopup()
{
    PopupContent = new AboutViewModel();
    IsPopupVisible = true;
}

You can display it using a Popup object, or a custom UserControl. I prefer to use my own custom Popup UserControl, which will usually end up looking like this:

<Window>
    <Canvas x:Name="RootPanel">
        <SomePanel>
            <!-- Regular content goes here -->
        </SomePanel>

        <local:PopupPanel Content="{Binding PopupContent}"
            local:PopupPanel.IsPopupVisible="{Binding IsPopupVisible}"
            local:PopupPanel.PopupParent="{Binding ElementName=RootPanel}" />
    </Canvas>
</Window>

The PopupContent property is a ViewModel (such as an AboutViewModel), and DataTemplates are used to tell WPF to draw specific ViewModels with specific Views

<Window.Resources>
    <DataTemplate DataType="{x:Type local:AboutViewModel}">
        <local:AboutView />
    </DataTemplate>
</Window.Resources>

The other method is to have some kind of ApplicationViewModel that runs on startup, and is responsible for the overall application state, which includes which window(s) are open.

Typically I prefer to have a single ApplicationView that contains a ContentControl to display the current page

<Window>
    <ContentControl Content="{Binding CurrentViewModel}" />
</Window>

however it can also be used to manage multiple windows. If you do use it to manage multiple Window objects, be warned that this will not be a pure ViewModel because it will need to access some View-specific objects, and referencing UI objects it not something a ViewModel should do. For example, it may subscribe to receive ShowWindow messages, and upon receiving those messages it would create the specified View and show it, and possibly hide the current window as well.

Personally, I try to avoid multiple windows as much as possible. My usual method is to have a single View that contains consistent application objects for any page, and a ContentControl containing dynamic content that changes. I have an example using this navigation style on my blog if you're interested

like image 102
Rachel Avatar answered Oct 18 '22 10:10

Rachel