Also see

Dynamically Creating Views

When using "View Model Style" programming, you may find a need to dynamically create Views. The challenge is to create them dynamically, while also allowing a Designer to easily design the UI.

View Model Style

View Model Style allows a programmer to create an application that has absolutely no UI (user interface). The programmer only creates a View Model and a Model. A designer with no programming ability at all is then able to start with a blank page and completely create the View (UI) in Microsoft Expression Blend 4 (or higher).

The Application

This application allows you to create unlimited Tabs, that each contain an editable Task.

The Web Service

While we normally use a View Model so that we don't need to change the UI when the design changes, if the basic requirements change, we usually need to actually change the code. In this case, the requirements have changed.

For the Web Site, the only code that needed to be changed was the Web Service code. The GetsTask method was removed, and the GetTasks method was altered to return the Task Description.

The Model

The Model was altered to not use Rx Extensions. While the code works either way, I was shown code by Richard Waddell and Shawn Wildermuth that requires about the same amount of code as Rx Extensions but does not require you at add any additional assemblies:

The View Model

This is where a lot of changes were made. Instead of one View Model, we now have three (we also have three Views).

Each View Model handles a different part of the application. Here is the overview:

MainPageModel.cs - This is the View Model for the main View that loads all the other embedded Views. The Add New Task button is on the View of this View Model, but it calls an ICommand that is in the TabControlModel's View Model (using View Model to View Model Communication described in this article: Silverlight View Model Communication).

TabControlModel.cs - This View Model dynamically creates TabItems and places an instance of the TaskDetails View, and its View Model (TaskDetailsModel.cs) on the TabItem.

TaskDetailsModel.cs - This View Model holds the details of a single Task.

MainPageModel

This class does not contain a lot of code. It mostly contains a property (TabControlVM) that will hold an instance of the TabControlModel.

This allows the MainPage View to call methods in the TabControlModel through its View Model (MainPageModel). This View Model to View Model Communication technique is covered in this article: Silverlight View Model Communication.

TabControlModel

This class performs 90% of the work of the application.

The main purpose of this View Model is to expose the collection of Tasks to the View. In the original RIA Tasks application, this collection was ObservableCollection<Task>, but, for RIA Tasks 2 we decided to use the Tab Control and expose a collection of TabItems (ObservableCollection<TabItem>):

The constructor for the View Model calls the GetTasks() method when the View is loaded:

public TabControlModel()
{
AddNewTaskCommand = new DelegateCommand(AddNewTask, CanAddNewTask);
DeleteTaskCommand = new DelegateCommand(DeleteTask, CanDeleteTask);
UpdateTaskCommand = new DelegateCommand(UpdateTask, CanUpdateTask);
// The following line prevents Expression Blend
// from showing an error when in design mode
if (!DesignerProperties.IsInDesignTool)
{
// Get the Tasks for the current user
GetTasks();
}
}

The constructor also sets up the ICommands that are used to Add, Update and Delete Tasks.

Note: This method first sets all TabItems' IsSelected to false, then sets the new TabItem's IsSelected to true. This is how you make a Tab Control programmatically select a tab.

The SetToNewTask() method calls the CreateTaskItem(objTask) method (shown below) that converts a Task to TabItem. The SetToNewTask() method then adds the TabItem to the colTabItemscollection (the Tab Control on the View is bound to this collection so that it can show the tabs):

The CreateTaskItem(objTask) method creates an instance of the View, TaskDetails, and an instance of its View Model, TaskDetailsModel, and sets the current Task for it to the selected Task (using the SetCurrentTask(Task) method).

It then places this View on a dynamically created TabItem (it sets the View as the Content of the TabItem).

It then returns the TabItem so that the SetToNewTask() method can add it to the colTabItems collection.

Note: the line objTabItem.Style = (Style)App.Current.Resources["TabItemStyle1"]; is used to allow a Designer to alter the style of this dynamically created TabItem by changing the style for the key TabItemStyle1. In the RiaTasks2.zip project, that style is in the "RIATasks\Assets\TabControl.xaml" file.

TaskDetailsModel

The TaskDetailsModel View Model is very simple. It contains a property to hold the current Task and a method that allows it to be set:

Note: The reason this class contains a method to set the Task property is that the View that is bound to the Task property will not update if you dynamically create the Viewand attempt to set the Task property directly.

The View

We will now create the Views.

Here is the overview:

MainPage.xaml - The View that loads all the other Views.

TabControl.xaml - The View that contains the Tab Control and displays the Tabs.

TaskDetails.xaml - The View that displays a single Task in a Tab.

MainPage View

MainPage contains an Add New Tasks button.

We drop an InvokeCommandAction behavior on the button.

When we Data bind the Command parameter of the behavior...

...we see that we are able to bind the ICommand that is in the TabControlModel View Model (that is stored in the TabControlVM property).

We can then go to Assets and drag and drop the TabControl View Model onto the page...

TabControl View

While the View Model for this View does most of the work for the application, the View is actually very straightforward.

The buttons are bound to the appropriate ICommands (using InvokeCommandAction behaviors), and the Tab Control is bound to the colTabItems collection.

It is important to note that the Update and Delete buttons, pass as a parameter, the currently selected TabItem (actually, they pass the Content of the TabItem which is the TaskDetails View and View Model).

This is how the methods know what Task to Update or Delete.

TaskDetails View

The binding for this View is also really simple.

However, this demonstrates the power of View Models:

The TabControlModel creates a Task and binds it to a dynamically created instance of the TaskDetailsModel

It then places it in a collection of TabItems and the Tab Control is bound to it

To Update or Delete the Task, the View is simply passed as a parameter to the appropriate method

Alternate Styles

The primary reason for using a View Model, besides that it is usually less code than using the code-behind style, is that you decouple the View from the code and allow a designer to create and re-create the View without altering any code.

Alan Beasley provided a style for the tabs and the buttons. The Tabs style styles the Tabs in all four positions (RIATasks2ABVersion.zip). To use it, we only needed to alter the resource files in the Assets directory. We have also specified the Tab Control to display the Tabs on the left side. This property is a standard property of the Tab Control.

Haruhiro Isowa created a Tab Control (RiaTasks2Hiro.zip) that displays all the Tabs on one scrollable row. He did have to create code to make his Tab Control scrollable, but the RIA Tasks 2 code was not altered at all (other than the .xaml files that the Designer would normally modify).

View Model - Not Hard At All

Hopefully you can see that View Model is not hard at all. It really is not complicated once you see how it is done. Expression Blend was designed to work in "View Model Style", so you should have an easier time using Expression Blend when you use this simple pattern.

We also demonstrated View Model Communication that you will hopefully find easy to understand. In addition, we covered dynamically creating Views while allowing a Designer full easy access to completely change the look of the application.

I've been playing with computers since my first Acorn Electron, & after blowing up a few ZX Spectrums. I moved on to the C64 & Amiga, & eventually reluctantly on to the PC.

I have learnt a wide set of skills during my 38 years of existence, living in the UK, on the sunny south coast.

My main area of expertise is Graphic/Visual Design, Usability & UI Design. I am not a programmer, but am fairly technically minded due to studying Mechanical Engineering at Uni.

I have work both Freelance & for IBM as a Graphic Designer, & am skilled in the usual graphics packages like, PhotoShop, CorelDraw or Illustrator, Premier, Dreamweaver, Flash etc.
But I originally started with Lightwave & 3D animation.