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 :)
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.
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.
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.
No that is fine; each object should be a ViewModel in its own right.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With