2 out of 4 rated this helpful - Rate this topic

Basic MVVM QuickStart

The Model-View-ViewModel (MVVM) pattern is a simple approach to separating the state and logic that support a view into a separate class named a ViewModel. The view model sits on top of the application data model to provide the state or data needed to support a single view to that view, insulating the view from needing to know about the full complexity of the application. The view model also encapsulates the interaction logic for the view that does not directly depend on the view elements themselves.

A common approach to designing the views and view models in an MVVM application is the first sketch out or storyboard for what a view looks like on the screen. Then you analyze that screen to identify what properties the view model needs to expose to support the view, without worrying about how that data will get into the view model. After you define what the view model needs to expose to the view and implement that, you can then dive into how to get the data into the view model. Often, this involves the view model calling to a service to retrieve the data, and sometimes data can be pushed into a view model from some other code such as an application controller.

This QuickStart leads you through the following steps:

  • Analyzing the view to decide what state is needed from a view model to support it
  • Defining the view model class with the minimum implementation to support the view
  • Defining the bindings in the view that point to view model properties
  • Attaching the view to the view model

Business Scenario

The main window of the Basic MVVM Application QuickStart represents a subset of a survey application. In this window, an empty survey with different types of questions is shown; and there is a button to submit the questionnaires. The following illustration shows the QuickStart main window.

MVVM QuickStart user interface

Gg430857.1B32E67148AE678ADB22AEB59CBA6C73(en-us,PandP.40).png

Building and Running the QuickStart

This QuickStart requires Microsoft Visual Studio 2010, Silverlight 4, and the Silverlight 4 Tools for Visual Studio 2010.

To build and run the MVVM QuickStart

  1. In Visual Studio, open the solution file Quickstarts\BasicMVVM\BasicMVVMQuickStart.sln.
  2. Make sure that the BasicMVVMApp.Web project is set as the Startup project.
  3. On the Build menu, click Rebuild Solution.
  4. Press F5 to run the QuickStart.
    Gg430857.note(en-us,PandP.40).gifNote:
    If you see the dialog box that prompts "Do you want to enable Silverlight debugging for this project?", click Yes. Otherwise, the output of this application will not be logged in the Visual Studio Output window.

Walkthrough

To explore the scenario, perform the steps to build and run the QuickStart:

  1. The main window is composed of a view that shows a questionnaire composed of different types of questions. The questionnaire can be submitted. The following illustration shows the main window.

    QuickStart main window

    Gg430857.1B32E67148AE678ADB22AEB59CBA6C73(en-us,PandP.40).png

  2. Enter information into the Name and Age boxes, and then respond to the questions in the questionnaire.
  3. Select your favorite color. The following illustration shows a completed questionnaire.

    The completed questionnaire

    Gg430857.D3A5BE05B8C7AD208EF8C1DBCFA89CBE(en-us,PandP.40).png

    Notice how the "color" text in the question changes its foreground to the selected color.

  4. After you complete the questionnaire, click the Submit button to submit your answers. The results of the questionnaire will be displayed in the output window of Visual Studio, as shown in the following illustration.

    The output of the completed questionnaire

    Gg430857.64A0290B467036CB8B4196767012B704(en-us,PandP.40).png

Implementation Details

The QuickStart highlights the key elements and considerations to implement the MVVM pattern in a basic application.

Analyzing What Properties Are Needed on the View Model

Open the QuestionnaireView in the designer. The list of color selections will be dynamically populated. When analyzing a view to define a view model, you want to identify each individual item of data and behavior that you need. In this case, assuming the questions are fixed and will not be dynamically driven, you need the following properties exposed from your view model:

  • Name: string
  • Age: int
  • Quest: string
  • FavoriteColor: string
  • Submit: Command

Because the first four properties are related to questionnaires, a questionnaire class is created to store them. The questionnaire class will be the model of the application, and the view model will only expose a property of type Questionnaire to support them.

Note that even things like buttons represent something that needs support from the view model. You can either expose a command, as shown in this QuickStart, or you can expose a method. With the former, you will need a property exposed from the view model with an object that implements the ICommand interface; with the latter, you need a behavior that can target a method.

Gg430857.note(en-us,PandP.40).gifNote:
For button clicks, you have the choice of commands or behaviors. For more information, see "Command-Enabled Controls vs. Behaviors" in Chapter 5, "Implementing the MVVM Pattern." In this topic, you will use a command. To do that, you need a command implementation, which does not exist in a form compatible with view models in the .NET Framework and Silverlight. Prism provides the DelegateCommand class that is perfect for hooking up views to view models with commands.

Implementing the View Model to Support the View

Open the QuestionnaireViewModel.cs file. The following properties are implemented in the view model.

public Questionnaire Questionnaire
{
    get { return this.questionnaire; }
}
public ICommand SubmitCommand { get; set; }

The INotifyPropertyChanged interface is implemented on the model, in the Questionnaire class. The property changed notification is only added to the FavoriteColor property, as shown in the following code.

public class Questionnaire : INotifyPropertyChanged
{
    private string favoriteColor;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Name { get; set; }

    public int Age { get; set; }

    public string Quest { get; set; }

    public string FavoriteColor
    {
        get
        {
            return this.favoriteColor;
        }

        set
        {
            if (value != this.favoriteColor)
            {
                this.favoriteColor = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs("FavoriteColor"));
                }
            }
        }
    }
}
Gg430857.note(en-us,PandP.40).gifNote:
The INotifyPropertyChanged interface is typically implemented in the view model class. In this particular example, it is implemented in the model because the property that needs to update the view when its value is changed is stored in the model.

As you can see, to support INotifyPropertyChanged, you need to implement the interface, define the PropertyChanged event, and expand each property to have a backing member field and fire the PropertyChanged event when the value changes. The interface is implemented so that the favorite color property changes the value of the "color" word in the user interface to the selected one. In any view where the data might change in the view model and you want those changes to be reflected on the screen, you need to implement this pattern for all the properties in the view model. Manually writing all this can take a lot of time. There are numerous code examples on the Internet that will generate this property pattern for you.

The questionnaire property, the collection property, and the command property are initialized in the view model class constructor.

public QuestionnaireViewModel()
{
    this.questionnaire = new Questionnaire();
    this.AllColors = new[] { "Red", "Blue", "Green" };
    this.SubmitCommand = new DelegateCommand<object>(this.OnSubmit);
}

Collection properties should always be initialized to either an empty collection or, if it is appropriate, to populate the collection in the constructor, you can do so, typically by calling a service. If you do that, make sure you do so in a way that will not break the designer. For more information about how to do that, see Blendability.

Additionally, if you expose ICommand properties that the view can bind command properties to, you need to create an instance of a command object. In this case, because you will use the DelegateCommand type from Prism, you need to create an instance of that and point it to a handling method. DelegateCommand also has the ability to carry along a strongly typed parameter if the CommandParameter property of a source control is also set. This is not used in the QuickStart, so the argument type is just specified as object.

The following code shows the OnSubmit handler method.

private void OnSubmit(object obj)
{
    Debug.WriteLine(BuildResultString());
}

To keep the solution simple, this handler method returns the values entered for the questions to the Output window in Visual Studio with the help of a helper method that is already implemented in the view model class. A real implementation of a command handler would typically do something like call out to a service to save the results to a repository or retrieve data if it was a Load type of operation. It might also cause navigation to another view to occur by calling to a navigation service.

Wiring Up the View Elements to the View Model

The bindings in the view elements point to the view model properties, as shown in the following table.

Element name

Property

Value

NameTextBox

Text

{Binding Path= Questionnaire.Name, Mode=TwoWay}

AgeTextBox

Text

{Binding Path=Questionnaire.Age, Mode=TwoWay}

Question1Response

Text

{Binding Path=Questionnaire.Quest, Mode=TwoWay}

ColorRun

Foreground

{Binding Questionnaire.FavoriteColor, TargetNullValue=Black}

Colors

ItemsSource

{Binding Path=AllColors}

Colors

SelectedItem

{Binding Questionnaire.FavoriteColor, Mode=TwoWay}

SubmitButton

Command

{Binding SubmitCommand}

Creating the View and View Model and Hooking Them Up

Open MainPage.xaml and look for the code where the view model is instantiated. To instantiate the view model in XAML, the view model class must have a default constructor. The XAML instantiation is shown in the following code.

<my:QuestionnaireView Grid.Row="1">
    <my:QuestionnaireView.DataContext>
        <my:QuestionnaireViewModel/>
    </my:QuestionnaireView.DataContext>
</my:QuestionnaireView>

This code creates an instance of the view type as a child of the MainPage, and then it sets its data context to an instance of the view model. There are many ways to hook up views to view models; for more information, see Chapter 5, "Implementing the MVVM Pattern."

Next Steps

The MVVM QuickStart is a more advanced version of this questionnaire that includes a view model that has the following things above and beyond what this view model has:

  • Dynamic composition of the questionnaire from multiple question types
  • Dynamic association of child views with child view models through a data bound collection of view models and data templates for the views
  • Validation of user input
  • Abstraction of the model through an async service

The MVVM Reference Implementation (MVVM RI) has an even more complete implementation of this scenario that includes a richer model that does not have to be wrapped as much by the view model and some basic navigation between multiple views backed with view models.

More Information

For more information about implementing the MVVM pattern, see the following chapters:

To learn about other QuickStarts included with Prism, see the following topics:

Last built: August 28, 2012

Did you find this helpful?
(1500 characters remaining)
© 2013 Microsoft. All rights reserved.