Click here to Skip to main content
15,868,141 members
Articles / Desktop Programming / WPF

MVVMLight Using Two Views

Rate me:
Please Sign up or sign in to vote.
4.61/5 (27 votes)
16 Oct 2012CPOL3 min read 164.5K   8.3K   62   27
How to create an MVVM application using MVVM Light with multiple views in one window

KB/Blogs/323187/mvvmlight_view1.png

In the previous article, I quickly showed how to create a single-view, single-window WPF application using MVVM Light. The trend in WPF applications is to have a single window holding multiple views so that there are less pop-up dialogs or child windows. This article shows how to construct a simple two view application using MVVM and WPF.

Getting Started

  • Requires VS2010
  • Ensure that you have Nuget installed
  • Manage Nuget Package References and add MVVM Light
  • The example code for this article is on github

Note that the XAML, in particular, is elided for brevity and you should go to the git repository for the original code.

Hosting Multiple Views

The application structure is similar to the previous article: we have a MainWindow, a ViewModelLocator, and a MainViewModel.

A picture is worth a thousand words, so without further ado, here is what the project structure looks like in VS2010:

KB/Blogs/323187/mvvmlight_vs.png

The project is laid out in typical MVVM style: 3 folders for Models, ViewModels, and Views. In this case, we do not have any Models so they can be ignored.

Starting with the Views: we simply have two UserControl XAML files, that contain the views that we want to render. The first view is the one from the previous article. The second is just a text label.

All the work involved in rendering two different views for two different view-models happens in MainViewModel.cs, MainWindow.xaml, and App.xaml.

Looking at the MainWindow XAML, we see the following;

XML
<Window x:Class="TwoViews.MainWindow"
        DataContext="{Binding Main,
                              Source={StaticResource Locator}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

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

        <DockPanel Grid.Row="1" >
            <Button Command="{Binding SecondViewCommand}"
                    Content="Second View"
                    DockPanel.Dock="Right" />
            <Button Command="{Binding FirstViewCommand}"
                    Content="First View"
                    DockPanel.Dock="Left" />
        </DockPanel>
    </Grid>
</Window>

As before, we use the ViewModelLocator to bind our Main view model to the MainWindow. This time, however, we have a ContentControl that binds to a new property called CurrentViewModel, and two buttons that bind to commands that switch the view models. Even though the buttons are labelled as switching the views, it is actually the view-models that are updated.

The next step in getting this to work is implementing a DataTemplate, per view model that renders a View associated with a ViewModel. We do this in the App.xaml (though we could do it in any Resource section we choose):

XML
<Application x:Class="TwoViews.App"
             xmlns:views="clr-namespace:TwoViews.Views"
             xmlns:vm="clr-namespace:TwoViews.ViewModels"
             StartupUri="MainWindow.xaml"
             >
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator"  />
        <DataTemplate DataType="{x:Type vm:SecondViewModel}">
            <views:SecondView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:FirstViewModel}">
            <views:FirstView />
        </DataTemplate>
    </Application.Resources>
</Application>

For example, this quite literally says ‘if my data type is FirstViewModel, then the WPF framework should render the FirstView UserControl.

So when the Content attribute of our the ContentControl is set to an object of type FirstViewModel, the framework renders the correct View for us.

It should also be noted that because the Content attribute has been set to a particular ViewModel, for example FirstViewModel, it is also set as the DataContext for the view that is rendered, i.e. FirstView, and the data-binding between FirstView and FirstViewModel therefore work.

The last part of the application that wires all of this together is the MainViewModel class. Clearly, we only want a single instance of each view model, so we just declare static instances of each one:

C#
public class MainViewModel : ViewModelBase
{
    private ViewModelBase _currentViewModel;

    readonly static FirstViewModel _firstViewModel = new FirstViewModel();
    readonly static SecondViewModel _secondViewModel = new SecondViewModel();

    public ViewModelBase CurrentViewModel
    {
        get
        {
            return _currentViewModel;
        }
        set
        {
            if (_currentViewModel == value)
                return;
            _currentViewModel = value;
            RaisePropertyChanged("CurrentViewModel");
        }
    }

    public ICommand FirstViewCommand { get; private set; }
    public ICommand SecondViewCommand { get; private set; }

    public MainViewModel()
    {
        CurrentViewModel = MainViewModel._firstViewModel;
        FirstViewCommand = new RelayCommand(() => ExecuteFirstViewCommand());
        SecondViewCommand = new RelayCommand(() => ExecuteSecondViewCommand());
    }         

    private void ExecuteFirstViewCommand()
    {
        CurrentViewModel = MainViewModel._firstViewModel;
    }

    private void ExecuteSecondViewCommand()
    {
        CurrentViewModel = MainViewModel._secondViewModel;
    }
}

Note that in the CurrentViewModel property, we also have to RaisePropertyChanged via the INPC interface that ViewModelBase defines. This is so that the data-binding works in WPF, i.e., when we click on the buttons, the view changes: if this line is omitted, you cannot change the views by clicking on the buttons.

If we run the code, we can now see that we can switch between the two views and both views maintain their state (as we are using a static instance of each):

KB/Blogs/323187/mvvmlight_view1.png

KB/Blogs/323187/mvvmlight_view2.png

Finishing Off

You might feel that the code above looks repetitive: it is. Many, if not all, MVVM frameworks provided ‘runtime assistance’ in automating this kind of thing. By that, I mean that by naming your classes according to convention, e.g. by always using the ‘View’ and ‘ViewModel’ suffixes, MVVM frameworks heavily use reflection and can associate your views and view-models at run time. Indeed, even the MainViewModel above is often generalized into something that is provided by the MVVM framework.

Footnotes

Previous articles/further reading:

The example code is on github.

This article was originally posted at http://www.lapthorn.net/archives/600

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
Jack of all trades.

Comments and Discussions

 
QuestionThx Pin
Neil Richardson11-Jan-17 9:02
Neil Richardson11-Jan-17 9:02 
QuestionCall to virtual method in constructor Pin
MTaunton19-Aug-16 23:26
MTaunton19-Aug-16 23:26 
QuestionWhat about Navigating View to View Pin
knick9-Sep-15 5:15
knick9-Sep-15 5:15 
AnswerRe: What about Navigating View to View Pin
Barry Lapthorn8-Oct-15 22:02
protectorBarry Lapthorn8-Oct-15 22:02 
QuestionDependency required ! Pin
M i s t e r L i s t e r19-Dec-14 10:50
M i s t e r L i s t e r19-Dec-14 10:50 
Questioncode behind view Pin
etwas779-Jul-14 23:51
etwas779-Jul-14 23:51 
GeneralMy vote of 2 Pin
reggaeguitar19-Jun-14 9:54
reggaeguitar19-Jun-14 9:54 
QuestionThanks! Pin
AndyCreigh21-Jan-14 6:41
AndyCreigh21-Jan-14 6:41 
GeneralMy vote of 3 Pin
b_in23-Oct-13 19:47
professionalb_in23-Oct-13 19:47 
QuestionHow come FirstView.xaml.cs contains the declaration for SecondView Pin
MarkTJohnson6-May-13 6:30
professionalMarkTJohnson6-May-13 6:30 
AnswerRe: How come FirstView.xaml.cs contains the declaration for SecondView Pin
DGlower4-Oct-13 2:05
DGlower4-Oct-13 2:05 
AnswerRe: How come FirstView.xaml.cs contains the declaration for SecondView Pin
Barry Lapthorn13-Nov-13 2:55
protectorBarry Lapthorn13-Nov-13 2:55 
Questiongrid name cannot be found in the name scope of 'System.Windows.Controls.Grid' Pin
Pedro Bessa11-Feb-13 11:19
Pedro Bessa11-Feb-13 11:19 
AnswerRe: grid name cannot be found in the name scope of 'System.Windows.Controls.Grid' Pin
Barry Lapthorn13-Feb-13 22:12
protectorBarry Lapthorn13-Feb-13 22:12 
QuestionA question about the ViewModelLocator Pin
roberto bandiera2-Feb-13 22:48
roberto bandiera2-Feb-13 22:48 
AnswerRe: A question about the ViewModelLocator Pin
Member 1078428529-Apr-14 11:11
Member 1078428529-Apr-14 11:11 
AnswerRe: A question about the ViewModelLocator Pin
alekcarlsen1-May-14 10:18
alekcarlsen1-May-14 10:18 
QuestionNothing to download? Pin
johan.s14-Oct-12 11:02
johan.s14-Oct-12 11:02 
AnswerRe: Nothing to download? Pin
johan.s14-Oct-12 11:08
johan.s14-Oct-12 11:08 
GeneralRe: Nothing to download? Pin
Barry Lapthorn16-Oct-12 8:13
protectorBarry Lapthorn16-Oct-12 8:13 
GeneralSimple but useful! Pin
kymo Wang8-Jun-12 1:48
kymo Wang8-Jun-12 1:48 
QuestionGreat... Pin
sidbaruah20-May-12 22:20
sidbaruah20-May-12 22:20 
AnswerRe: Great... Pin
Barry Lapthorn20-May-12 22:32
protectorBarry Lapthorn20-May-12 22:32 
GeneralMy vote of 5 Pin
Eduardo Mardini2-Feb-12 5:26
Eduardo Mardini2-Feb-12 5:26 
GeneralRe: My vote of 5 Pin
Barry Lapthorn2-Feb-12 5:40
protectorBarry Lapthorn2-Feb-12 5:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.