January 2015

.NET Musings

Wandering thoughts of a developer, architect, speaker, and trainer

NAVIGATION - SEARCH

A Template for WPF Windows with View Model Support

One of the really nice templates for Windows 8/8.1 and Windows Phone 8.1 development (C#/XAML) is the Basic Page.  Adding a Basic Page to your Win8.1/WP8.1 project brings in additional support files for navigation, commands, life cycle management, and an implementation of an observable dictionary.  These are awesome features that I cover in my book (Pro Windows 8.1 Development with XAML and C#) and my talks on Win8.1 and WP8.1.  I just realized that I haven’t blogged about those, so they are on my todo list!

The Basic Page View Model Support

The Basic Page template makes a subtle change to the page’s XAML by adding the DataContext attribute to the Page tag:

DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
Just in cases you are new to XAML, this sets the context for any subsequent binding calls on the page to a property named “DefaultViewModel”.  The RelativeSource statement is the XAML way of indicating that the property can be found on the page class itself. When we open up the code behind file, we see the following lines of code – well there’s actually a lot more to the basic page, but these are the lines we care about:
private ObservableDictionary defaultViewModel = new ObservableDictionary();
/// <summary>
/// This can be changed to a strongly typed view model.
/// </summary>
public ObservableDictionary DefaultViewModel
{
   get { return this.defaultViewModel; }
}
I have found this little tweak very helpful in my Win8.1/WP8.1 development.  I merely change the type of the DefaultViewModel to the type that I want (e.g. MainPageViewModel) and I’m done. 
private MainPageViewModel defaultViewModel = new MainPageViewModel();
/// <summary>
/// This can be changed to a strongly typed view model.
/// </summary>
public MainPageViewModel DefaultViewModel
{
	get { return this.defaultViewModel; }
}
There is of course a lot more to this pattern, and this is a very simple way of using it.  But I do like the way this is implemented, and after having worked with Win8.1/WP8.1, I’ve grown to expect it to be there. I know you are thinking – isn’t this post about WPF?  Yes it is, but I felt I needed to answer the “Why does this template help me” question before showing you the template.

Creating a Template in Visual Studio

I recently fired up a new WPF app for a client, and realized that the Basic Page template didn’t exist. It didn’t take me long to realize that the vast majority of what comes along with the Basic Page template (such as life cycle management, navigation, etc.) either doesn’t apply at all or only mildly applies.  But I miss the DefaultViewModel pattern the Basic Page brought to the table.

So let’s create one.  Of course in WPF we use Windows and not Pages.  (Well, there are Pages in WPF, but the navigation model was never really flushed out for WPF.  Maybe with Microsoft ramping up the WPF/XAML team we will get that in a future version.)

Create the Window for the Template

  • Create a new WPF Project File-> New Project… Select WPF Application (under Templates –> Visual C# || Visual Basic –> Windows Desktop). Call it anything you want, it doesn’t really matter. 
  • Right click on the project and select Add –> New Item…, select Window (WPF). Name it Window1.xaml.
  • Open Window1.xaml
  • Update the XAML in the Window tag to add the DataContext.  I also add a Startup location because I like my WPF apps to be centered when they start. Your new XAML for the Window should look something like this (the namespace will most likely be different):
<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window" Height="300" Width="300"
	DataContext="{Binding Path=DefaultViewModel, RelativeSource={RelativeSource Mode=Self}}"
	WindowStartupLocation="CenterScreen">
    <Grid>
 
    </Grid>
</Window>
  • Open Window1.xaml.cs
  • Add property for the view model with a public getter and private setter.
  • Your class should look something like this:
namespace WpfApplication1
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    private Object _defaultViewModel = new object();
    public Window1()
    {
      InitializeComponent();
    }
 
    public Object DefaultViewModel
    {
      get { return _defaultViewModel; }
      private set { _defaultViewModel = value; }
    }
  }
}

Create The Template

Creating the template is a straight forward process.  The secret sauce comes in editing the template before importing it into Visual Studio.

  • Select the file that you just created (and modified) in Solution Explorer
  • Click File –> Export Template…
  • Select Item template, click Next.

image

  • Select the file to use (Window1.xaml) and click Next.

image

  • Select System, WindowsBase, PresentationCore, PresentationFramework references. Click Next.

image

  • Update the Template name and the Template description
  • Make note of the output location.
  • Make sure you uncheck “Automatically import the template into Visual Studio”
  • Click Finish

image

Update the Template files

Navigate to the location shown in the output location and extract the files in the zip into a new directory.

MyTemplate.vstemplate
  • Edit MyTemplate.vstemplate
  • In the TemplateData section, change the default name to Window.xaml
  • Add tags for TemplateGroupID (category to be displayed under), NumberOfParentCategoriesToRollUp (how far above the category it should be dispalyed), RequiredFrameworkVersion.
      <TemplateData>
    
        <DefaultName>Window.xaml</DefaultName>
    
        <Name>WPF Window With VM</Name>
    
        <Description>WPF Window with view model plumbing</Description>
    
        <ProjectType>CSharp</ProjectType>
    
        <SortOrder>10</SortOrder>
    
        <Icon>__TemplateIcon.ico</Icon>
    
        <RequiredFrameworkVersion>3.0</RequiredFrameworkVersion>
    
        <NumberOfParentCategoriesToRollUp>1</NumberOfParentCategoriesToRollUp>
    
        <TemplateGroupID>WPF</TemplateGroupID>
    
      </TemplateData>
  • Save the file
Window1.xaml
  • Open Window1.xaml.
  • Change the Title to $safeitemname$.  This will make the title of the window the same as the file name (minus the extension).
  • Save the file
Window1.xaml.cs
  • Open Window1.xaml.cs
  • Update the usings for System.Linq and System.Threading.Tasks to the following:
$if$ ($targetframeworkversion$ >= 3.5)using System.Linq;
$endif$
$if$ ($targetframeworkversion$ >= 4.5)using System.Threading.Tasks;
$endif$
  • Save the file

Add the Template to the Visual Studio 2013 templates directory

You can add the template from a number of different locations.  In this example I am going to add them to the User item templates.  This location is determine through Visual Studio Tools –> Options –> Projects and Solutions –> General. The default location is ..\Users\[username]\Documents\Visual Studio 2013\Templates\ItemTemplates\.

  • Copy the entire directory containing the expanded files from the original zip
  • Navigate to ..\Users\[username]\Documents\Visual Studio 2013\Templates\ItemTemplates\
  • Create a directory (if it doesn’t exist) called “Visual C#”
  • Create a directory under the “Visual C#” directory called “WPF”
  • Copy the directory and the template files from the previous step into the “WPF” directory.

Make Visual Studio 2013 aware of the new template

The final step is to make Visual Studio aware of the new templates.  Unfortunately (or fortunately) VS doesn’t scan the template folders automatically on startup.  I think it’s fortunate, because VS is already doing a lot of work on startup.

  • Close any instances of Visual Studio that you have running
  • Running a command prompt as administrator
  • Navigating to the install directory for Visual Studio (%ProgramFiles(x86)%\Microsoft Visual Studio 12.0\Common7\IDE)
  • Run “denev /installvstemplates”.  Be prepared to wait for a long time for it to complete.
  • Close the command window.

Test the Template

  • Open Visual Studio
  • Open a (or create a new) WPF project.
  • Right click on the project, and select Add –> New item…
  • Since we set the Rollup level to one (1), you will see the template in the main Visual C# list of templates.
  • Click on WPF to make sure it is there as well

image

Summary

There is a lot more that can be covered with Item and Project Templates, and you can also use Template Builder to create much more robust templates and make sharing them easier.  For more information on Template Builder and Side Waffle, listen to my Hallway Conversations podcast episode where we interview Sayed Hashimi. Download my version of the template here.

About the author

Philip Japikse

Philip Japikse An international speaker, Microsoft MVP, ASPInsider, MCSD, CSM, and CSP, and a passionate member of the developer community, Phil Japikse has been working with .NET since the first betas, developing software for over 30 years, and heavily involved in the agile community since 2005. Phil is the Principal Architect for InterKnowlogy (http://www.InterKnowlogy.com), helping an amazing team create high impact software experiences. Phil serves as the Lead Director for the Cincinnati .NET User’s Group (www.cinnug.org)and the Cincinnati Software Architect Group, co-hosts the Hallway Conversations podcast (www.hallwayconversations.com), founded the Cincinnati Day of Agile (www.dayofagile.org), and volunteers for the National Ski Patrol. Phil is a frequent speaker all over the world, from User Groups and Meet ups to large scale professional conferences. You can follow Phil on twitter via www.twitter.com/skimedic and read his blog at www.skimedic.com/blog.
 

 

Managed Windows Shared Hosting by OrcsWeb