Click here to Skip to main content
Click here to Skip to main content

The big MVVM Template

, 5 May 2014
Rate this:
Please Sign up or sign in to vote.
To save you doing this every time you want a WPF/MVVM project, here it is, all rolled into one.

Project was built with VS 2013. The code is fully commented, so you can just go through it and it'll be easy to figure out what's happening where.

Feel free to download and play with the code.
If you do, and you find it helpful, please come back and vote or comment Smile | :)

Introduction

If you ever wanted to start a little project (or a big one), and got annoyed with the plumbing involved with the whole WPF-MVVM plumbing involved, this article is for you.

If you're new to MVVM, and want to have a quick look at what you can achieve, by all means, grab the code, and read through it. It is fully commented, and covers lots of different topics.

So, what do we have here?

Most of the things aren't my own inventions, but what you have here is a whole lot of different things together under the same roof, so when you want to start something, you can quickly use this and just replace what you need or remove what you won't use.

Here's a quick overview of what's Included:

  • MVVM Light & .Net 4.5
  • INPC implementation in base view model.
  • Menu
  • Tab Control (MVVM + binding of tap per View)
  • Enumerations
  • Random data for mocking and prototyping
  • Using Commands to bind buttons to View Model
  • Enable / Disable buttons
  • Validations (Text boxes / input fields)
  • Converters
  • Styles
  • DataTemplates
  • Resources (images, txt)
  • Extension methods
  • Random helpers
  • DataService & DI (from MVVM Light)
  • Unit Testing

You'll probably won't use all of these, but it's so much easier to just have it there and cut out what's not needed, than trying to remember how to make Resharper play nice with MVVM Light, how to make RaisePropertyChanged work without supplying it the name of the property as a string, which files need to be referenced, and so on.

I'm in, what's next?

Download the code, run the solution, and start hacking away. In the following sections I'll highlight what's included, why is it there, and how to use it if needed.

The Red Pill or the Blue Pill?

I'm a Grasshopper:

Please, show me the ropes, hold my hand and take me for a stroll around

--> Start with the background.

I'm a Ninja:

I've been collecting Microsoft MVP's when you were still struggling to write your first "Hello World!".

--> Jump to what's interesting in each part.

MVVM pattern

Background

What's all this MVVM I keep hearing about?? Well, as the picture to the right shows, it's a pattern that will decouple your views from your model, and make everything easy to unit test. In other words, less time fixing broken code, and more time sunbathing in Hawaii.

The benefits of MVVM (amongst others, are the power binding from the View (in XAML) to the ViewModel (your C# code), which is intended to free coders from how the design works, and designers from how the code works. You can prototype what you want, tell your dev guy: I want a class with a property Foo of type int, and Bar of type string. Then you go to your design guy and tell him: I want a page that looks like that, here is what you'll bind to: a Property Foo of type int, and Bar of type string.

My only issue with WPF/MVVM is the amount of plumbing necessary to start coding. Common examples would be:

  • How do I add a Validation rule ...
  • How do I define a Converter ...
  • What was the command syntax again ...
  • How do I bind to ViewModel ...
  • How does the Messenger works ...

Usually once I'm past those, I'll spend some time mocking data for the Design Time, and so on. You should get the point by now ... lot's of plumbing ...

General structure

  • Auxiliary (top level for all misc folders)
    • Converters
    • Helpers (Extensions methods, etc.)
    • Resources (Files, dlls, pictures, etc.)
    • Validations
  • Design Time (Central folder for all design time files)
  • Models
  • ViewModels
  • Views

Climbing down the (project) tree:

Properties

I've added the Annotations.cs to the Properties, in order to facilitate calling the `RaisePropertyChanged` without specifying which property is changing. The reason is to avoid simple yet annoying and hard to find bugs that happen when you decide to change your property name, but forget to change the name on the `RaisePropertyChanged` string parameter.

Converters

These are basically classes that inherit from IValueConverter. The idea is simple, you supply the Convert method with the input, and you get to control the Output.
What is this useful for?

  • You have a DateTime Property and you want to display only the year.
  • You have a number property for letting the user know how many Unicorns he has, and you want to be able to say "No Unicorns", "A Unicorn", "Some Unicorns" depending on that number.
For example:
class CommentsConverter : IValueConverter
{
  /// <summary>
  /// An example for a converter that will return 
  /// "Warning: Wild Unicorns found on premise." 
  /// if the word "unicorn" exists in the string.
  /// </summary>
  public object Convert(object value,Type targetType,object parameter,CultureInfo culture)
  {
    var input_string = value as string;
    if (input_string.IsNullOrEmpty()) 
      return "The cake is a lie.";
    if (input_string.Contains("unicorn"))
      return "Warning: Wild Unicorns found on premise.";
    
    return "This following text is Unicorn free: [" + input_string + "]";
  }

  /// <summary>
  /// It it makes sense to convert back, IMPLEMENT the following method as well !!!!
  /// </summary>
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    throw new NotImplementedException();
  }
}  

To use the above converter, have this in your Xaml:

<TextBlock  
    Text="{Binding SomeProperty, Converter={StaticResource CommentsConverter}}" 
/> 

Helpers

Here are all the little classes that help you get your work done, but aren't that vital by themselves.

Enums.cs

You can have all your enumerations in one place, so you don't need to try and find them when you want to have a look at them.

MessengerClasses

This is used with MVVM Light in order to send Messages from one view to another. This class simply holds together a collection of specific classes that you will send as messages. Have a look at the code for fully documented examples.

Random_Helper

If you're sick of writing: Random rand= new Random(); before you can call rand.GetNext(); to get some random number (and hopefully not forget not to do this in a tight loop because you'll get the same number), I present: The Random_Helper.
It has all the random methods you can shake a stick at, and then some more. The benefit is that you can use them, add to them, or remove what you don't like, instead of creating them yourself to get some random data.

All are documented, so have a look in there. Some of the methods are:

  • RandomName
  • RandomDate
  • RandomPhone
  • RandomWeather
  • RandomBool

StringExtensionMethods

If you hate to write: string.IsNullOrEmpty(some_string) , and love Linq syntax like: some_string.IsNullOrEmpty(), you'll love these.

Extensions methods a basically syntactic sugar that allow you to access static methods as if they were part of a class usual methods/properties. Head to MSDN documentation if you never heard about them.

Validation_helper

The idea behind this is the assumption that your validations needs to do repetitive things in multiple validations (different classes). We can move all the duplicated code to a static helper, and simply call the methods from it.

Resources

All of your misc files will probably end up here. In this example, I have a picture, a text document, my styles and datatemplates, and another class (ApexGrid) that I'll be using as well

ApexGrid.cs

Normal XAML grids suck. Apex Grid will allow you to replace the following code:

 <Grid>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    <RowDefinition Height="28" />
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="200" />
  </Grid.ColumnDefinitions>
</Grid> 

With:

<a:ApexGrid Rows="Auto,Auto,*,28"  Columns="Auto,200" >
  <!-- Your code goes here -->
</a:ApexGrid> 
DataTemplates.cs

This is where we'll glue our ViewModels to our Views. Have a look in the source code for more examples and options to do some old style templating:

<!--   Here I'm binding ViewModels to Views, so the content         -->
<!--   controll will know what to display (on the view) when        -->
<!--   it encounters a ViewModel                                    -->
<DataTemplate DataType="{x:Type vm:About_ViewModel}">
  <views:About_View />
</DataTemplate>  
Styles.cs

One point to have all our styles declared together, in order to give the application a consistent look, and to avoid writing repetitive code that ends up breaking and out of synch.

<!-- Lets define a template for all of our labels for example: -->
<Style TargetType="Label" x:Key="MyLabelTemplate">
  <Setter Property="Foreground" Value="Yellow" />
  <Setter Property="Margin" Value="5"></Setter>
</Style>   

Validations

Similar to the converters, these are classes that extend ValidationRule. They will take an object, run some logic, and return a true/false result, which then might trigger a style if you want (In this template, it'll have a blinking red exclamation mark, which you can find in the "Styles.cs" if you want to see how it's implemented.

class Example_Validation : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var str = value as string;      // Convert to our string
        var sb = new StringBuilder();   // For the error messages
        var valid = true;               // Rather obvious
        
        if (str.Length < 5)       
        {
            valid = false;
            sb.AppendLine("String too short.");
        }

        return new ValidationResult(valid, sb.ToString());
    }
} 

Design Time

You can put all your design time classes here. In this template, I'm just reusing Laurent Bugnion and his MVVM Light template .

Basically, it holds a design time implementation of the DataService, and will return back fake local data, instead of the real DataService that will usually call a database or the web.

Models

Here you'll have all your model classes. If you're asking what's your model, you should do some reading on MVVM, but basically it's all your logic that interacts with the DB or the Web and doesn't care at all about how you present it to the user
In this example, you'll find there the IDataService Interface, the implementation (DataService), and a Person.cs class, which I'm using to fake people information at, but would come from the Database in a real world program.

ViewModels

In here you'll have all your ViewModels, which sit between the View and the Model, and act like a buffer so you don't mingle your UI with you Logic. All the ViewModels in the template are fully commented, and you can have a read to see what they do if you care.

Quick overview:

  • About_ViewModel.cs : my info, but you might want to have something similar
  • Main_ViewModel.cs : The properties that the MainWindow will bind to
  • MVVMLight_ViewModel.cs: Laurent's example, left it in so you can see what he did.
  • MyBase_ViewModel.cs: All our custom view models inherit from this, in order to support the INPC "magic"
  • Random_ViewModel.cs: First Tab, holds random data
  • ValidationsConverters_ViewModel.cs: Second Tab, with examples of validations and converters.
  • ViewModelLocator: Laurent's Locator. This is used as a static instance to get the other View Models.

Views

These are the files that hold the UI. Each View is a combination of a Xaml file and a Xaml.cs codebehind file. The only View with code behind is the About, and the reason is that I wanted to link back to the CodeProject. Depending on which side of the fence you are on regarding the "pureness" of the MVVM pattern, you might love or hate this.

Enter the Dojo

MainWindow and Main_ViewModel

This is the entry point to our program. The ViewModel (a.k.a: VM) holds other ViewModels as properties, and the View simply bind each TabItem to a VM.

The window is composed of a DockPanel, with a Menu docked to the top, a StatusBar docked to the bottom, and the last child which is the TabControl takes the rest of the space.

The MenuItems in the Menu use Commands to bind to either ApplicationCommands (Cut, Copy, Paste), or to actual methods on other VM's. In order to reach these other VM's we use MVVM Light's messenger class, sending a message of some type, which the other VM will register to receive and route to it's own Command.

Look at the code for examples and comments. Here's a snippet:

 <Grid x:Name="LayoutRoot">
    <DockPanel >
      <!--                                                           -->
      <Menu DockPanel.Dock="Top" ...       >
        <!--    Default application commands:   -->
        <MenuItem Header="_Default commands" IsTabStop="False">
          <MenuItem Command="ApplicationCommands.Copy" />
          <!-- ... -->
        </MenuItem>
        <MenuItem Header="_Custom commands" IsTabStop="False">
          <MenuItem Header="Refresh 7 people"
              Command="{Binding RefreshPeopleMenu_Command}" 
              CommandParameter="7"  />
          <!-- ... -->
        </MenuItem>
      </Menu>
    
      <StatusBar  DockPanel.Dock="Bottom" ...>
        <StatusBarItem HorizontalAlignment="Right">
          <TextBlock Name="StatBarText" Text="{Binding StatusBarMessage}" />
        </StatusBarItem>
      </StatusBar>
      <TabControl>
        <TabItem Header="Random Helper">
          <ContentControl Content="{Binding Random_VM}"  />
        </TabItem>
        <!-- ... -->
      </TabControl>
    </DockPanel> 

In the Main_ViewModel constructor, we're registering to listen to messages of type StatusMessage , so we can easily set the StatusBar text from any VM in the application:

 Messenger.Default.Register<StatusMessage>(this, msg => StatusBarMessage=msg.NewStatus); 

Random_View and Random_ViewModel

Top has a ComboBox which is Bound to an enum example. Nothing fancy.

The bottom part holds a DataGrid which holds some random objects of type Person (you can find the class in the Models folder). Besides binding to the properties of an object and displaying different properties of that object, the interesting thing is the Interaction.Triggers. Have a look at the code for more comments, but basically it uses Blend's dll's to enable your controls to react to clicks on them.
In our case, double clicking on the DataGrid will open a MessageBox with the name of the person you clicked on, but you can do whatever you want of course. As an extra bonus, you get the syntax to pass a parameter with the command (in our example, we bind it to the selected item).

Next we have an example of how to enable/disable a button using the CanExecute on the command . In this case it's a simple check that the parameter passed is bigger than 3, so if you'll choose the value "1" in the ComboBox, the button will be disabled.
To make sure that button is disabled as soon as we choose "1", we'll call the CommandManager.InvalidateRequerySuggested(); on the property it's bound to. This will refresh all the bindings and as a result, check the can execute of that button, and disable it. Look at the code comments for more info.

Just like in the main VM, we register the command to refresh the people with the Messenger using:

Messenger.Default.Register<RefreshPeople>(this, (msg) => Execute_RefreshPeople(msg.PeopleToFetch));  

This enables us to reuse this command and use it from the Menu (which is part of the Main_ViewModel, without hard coding the call).

Last, when the button is clicked, and the command to refresh the people is fired, we are sending a message to the messenger to set the status. I've set that method as static on the Messenger class, so you can call it from any VM, passing a string that you want to set the StatusBar to. The code for this is:

private void Execute_RefreshPeople(int arg)
{
    PeopelCollection = new ObservableCollection<Person>(_dataService.GetPeople(arg));
    var msg = arg + " people refreshed.";
    StatusSetter.SetStatus(msg);    //     <--   This sends the message
} 

ICommand:

Here I'm using a conventions that declares & initializes the command at the same time, saving you the need to initialize the command in the constructor. Here's an examlpe:

public ICommand SomeMethod_Command  
{  
    get  
    {
        return _someMethodCommand ??
             (_someMethodCommand = 
                new RelayCommand<int>(Execute_SomeMethod, 
                                      CanExecute_SomeMethod));
    }
}
private ICommand _someMethodCommand; 

ValidationsConvertes_View and ValidationsConvertes_ViewModel

Validations:

The idea behind these is to let the user know something is wrong with is input. You can use this to validate emails, make sure some fields are not empty and so on. It's been quickly covered above. In my Styles.xaml (under Auxiliary\Resources), I've defined a style called "myErrorTemplate" which targets "Control" (basically, everything). The idea is to use this is a base for other styles (in my case, for TextBox, CheckBox and ComboBox), so we'll get the same style applied to all input fields. It'll flash an exclamation mark 3 times and set the border of the control to red, so the user knows something is wrong. It also sets the tool tips with helpful messages to allow the user to understand what's the problem when he hoover over the control.
So, the top part with the 2 input fields takes care of that.

Converters:

The second part covers converts. It's been also covered above, so I'll be brief.
You have one TextBox in which you can write, and two TextBlocks that will show you in real time what the converter gets, and what it returns. There are 3 states this converter will react to: empty string, and whether or not the string contains the word "unicorn". Feel free to play around with it and look at the code.

Button Enable/Disable example:

Yes, I know, you're ninjas and you might have noticed this has been done already in the Random_ViewModel. Congratulations. Now keep reading.
As opposed to doing the check and setting the status in the viewmodel (code), here it's done via the xaml, using Style.Triggers.
The idea is you can take your control, and declare in the xaml what happens when certain events are true or false. You can set a single trigger, or multiple triggers (in the code you have both examples, so please look at it for more).
Here's an example with a single trigger on a button. If a property called ShouldBeEnabledProperty on the ViewModel is true, the button is enabled. If it's false, it'll be disabled. You can trigger this in the code, and assuming your property is an INPC and it fires a property changed, it'll automatically update the button to the right state when it happens.

<Button Content="Shiny name here" 
        Command="{Binding Path=Some_Command}" >
    <Button.Style>
       <Style TargetType="Button">
            <Setter Property="IsEnabled" Value="False"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=ShouldBeEnabledProperty}" Value="True">
                    <Setter Property="IsEnabled" Value="True" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button> 

ICommand:

This ViewModel uses a different convention for defining and initializing a command in the View Model. Declare a simple ICommand Auto Property, and then initialize it in the constructor like this:

public Your_ViewModel(IDataService dataService)
{
    ...
    // Inside the constructor:
    SomeMethod_Command = new RelayCommand(Execute_SomeMethod, CanExecute_SomeMethod);
    ...
}
// Outside, like a normal C# Property:
public ICommand SomeMethod_Command { get; private set; } 

I suggest picking the one you like best, and sticking with it.

MvvmLight_View and MvvmLight_ViewModel

This is the default template that comes with Laurent Bugnion and his MVVM Light template . I left it as a tab so you can see the Nuget package defaults and look at his code.
I've had the honour of briefly contacting him and he seems like a great guy. He was veryvery helpful even though he was very busy Smile | :) .

About_View and About_ViewModel

I created this for a different project, and it's a nice touch if you want to have an "About" view I think.The ViewModel is rather boring (one property as a stub for others), since it's not supposed to do much.

The interesting points would be:
1. Embedding an image (resource) to your View
2. Having a link that will open in a web browser (the computer's default). The gist of this is having an Hyperlink in the View, like this

<TextBlock >
     CodeProject:
    <Hyperlink NavigateUri="http://www.codeproject.com/Members/_Noctis_"
               RequestNavigate="NavigateToCP">
         link
    </Hyperlink>.
</TextBlock> 

Which will call this method on the code behind, which will start a new process and go to the link:

private void NavigateToCP(object sender, RequestNavigateEventArgs e)
{
    System.Diagnostics.Process.Start("http://www.codeproject.com/Members/_Noctis_");
} 

Unit Testing

Without Unit testing, I believe your project is doomed to failure, and shouldn't hit production. I've added a simple Unit Test project to the solution, just so you'll have no excuse of setting one yourself. It has some very simple test methods that will fetch some random data from the Random_Helper class, and do some basic validations.

If you've never done testing, grab some books, and jump on the wagon. It'll change the way you code, and save you heaps of time in the future.

Other important parts:

ViewModelLocator

This is the heart of the "dynamic" fetching and getting views and view models in MVVM Light. You should remember four things:

1. Have this in your App.xaml:

In App.xaml:
  <Application.Resources>
      <vm:ViewModelLocatorTemplate xmlns:vm="clr-namespace:MVVM_Template_Project.ViewModels"
                                   x:Key="Locator" />
  </Application.Resources> 

2. Have this in each view, so it'll know it's data context:

DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}" 

3. Register the class with the SimpleIoc (simple inversion of control) in the ViewModelLocator constructor:

SimpleIoc.Default.Register<Main_ViewModel>(); 

4. Have a property with the ViewModel in the ViewModelLocator:

public Main_ViewModel Main
{
    get
    {
        return ServiceLocator.Current.GetInstance<Main_ViewModel>();
    }
}  

Note: Duplicate Properties in ViewModelLocator and Main_ViewModel:

Because I'm not using the default MainWindow for everything, and because I have the Main_ViewModel which is used in the ViewModelLocator, you'll have to define your ViewModels properties in BOTH ViewModelLocator AND Main_ViewModel. They will both return the same Instance, but this is the reason why:

  • When you're binding in the VIEW, you're using the ViewModelLocator's property.
  • When you're binding in the MainWindow, you're using the Main_ViewModel property.

For example:

<TabItem Header="Some name">  
    <ContentControl Content="{Binding Some_VM}"  />
</TabItem>

Is using the Main_ViewModel's Some_VM Property, but when you bind it in the view's xaml:

DataContext="{Binding Test_VM, Source={StaticResource Locator}}" 

You're using the ViewModelLocator Property. Feel free to name them differently if it helps you.

If you're not using tabs, or ain't going to bind things in the main view model you can remove all the properties from the Main_ViewModel, and just have them in your ViewModelLocator.

Annotations.cs :

I've added the file Annotations.cs to the Properties, in order to facilitate calling the `RaisePropertyChanged` without specifying which property is changing. The reason is to avoid simple yet annoying and hard to find bugs that happen when you decide to change your property name, but forget to change the name on the `RaisePropertyChanged` string parameter.

Base Class:

Next, I've created MyBase_ViewModel that extends GalaSoft's ViewModelBase, with the RaisePropertyChanged and RaisePropertyChanging so that the above will work for all classes derived from it. Read: Use MyBase_ViewModel : ViewModelBase and not ViewModelBase as the base for your view models.

Application Icon

To set the application icon, simply go to your project's properties, and under the Application tab, set the Icon to any icon that you want (note, it has to be an ".ico" file, but you can easily run a google search and find free online websites that will convert your .jpg or .png to icons. Here are two:

Wrap up

This resulted in a much longer task than I've originally intended (believe it or not, I've intended to write a completely different project to begin with) but I believe this will be of much help to developers everywhere.

You can find most of the above plus more and in the code as comments, and in the "Readme.md" as well.

If you've found this article helpful, please vote for the article, leave a message, and feel free to post back to this article Smile | :)

History

  • 4 May, 2014: Initial release.

License

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

About the Author

_Noctis_
Software Developer
Australia Australia
Coding since I Remeber myself ... went through Basic on Commodore 64 to C# on an 8 core i7 ... In between worked with c, c++, java, assembler, php, pascal, JScript, SQL based DB's and a bit of NoSQL as well.
 
Love software, and I'm usually fidgeting around with technology software and hardware on my free time.
Follow on   LinkedIn

Comments and Discussions

 
QuestionGood Pinmembersyynapse30-Jun-14 3:21 
AnswerRe: Good Pinprofessional_Noctis_30-Jun-14 15:04 
GeneralDownloads work again [modified] Pinmember_Noctis_4-May-14 22:09 
Questionsource code file link broken PinmemberTridip Bhattacharjee4-May-14 21:24 
AnswerRe: source code file link broken Pinmemberjohannesnestler4-May-14 21:36 
GeneralRe: source code file link broken Pinmember_Noctis_4-May-14 21:43 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 5 May 2014
Article Copyright 2014 by _Noctis_
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid