Papa's Perspective

MVVM in 5 Minutes

Learn MVVM fundamentals by building this simple Twitter app.

Want to see Model-View-ViewModel (MVVM) without all the "helpers"? Perhaps you thought I was kidding in my previous column, "Fundamental MVVM". Now, I love helpers for things like commanding, behaviors, messaging and locators. But I'm holding to my earlier statement that these things help MVVM, which is all about separation; they do not make MVVM. That's an important distinction.

I admit that with all the conversation about how to develop with MVVM it's sometimes difficult to separate what is MVVM and what's just a helper. That's one of the reasons I'm writing about these topics. I think it's important to make that distinction first. Once you understand MVVM, you can decide which helpers you want to use. Otherwise you may go down the MVVM path only to feel like you got blasted backward with a fire hose.

So let's take a look at MVVM with no frills. This sample app is going to be the Hello

World of our generation: a Twitter app that will look something like the image in Figure 1.

Figure 1. The image created by the TimelineView.xaml of a Twitter app built using the Model-View-ViewModel pattern.

Model
My Twitter app needs tweets to appear in the main timeline. So the first thing I do is create a Model called Tweet. The Tweet class inherits from a class I call Observable-Object, which simply implements the INotifyPropertyChanged (INPC) interface. INPC is a simple interface that implements a PropertyChanged, which is what a Model needs to communicate to a View's controls that something about a property has changed. I could've implemented the INPC interface on the Model directly but I never do that in the "real world," so why bother here. I like the base class ObservableObject because it simplifies this process.

The rest of my Model has a series of properties that describe the Tweet, such as UserName. All of the properties call the RaisePropertyChanged method (which is on the ObservableObject class):

protected const string UserNameProperty = 
"UserName";
private string _userName;
public string UserName
{
  get { return _userName; }
  set
  {
    if (_userName != value)
    {
      _userName = value;
      RaisePropertyChanged(UserNameProperty,  	        
        TitleProperty);
    }
  }
}

The Model is a simple representation of the data. It's separated into its own class because I may have more than one View where I want to display tweet information. The separation fosters the reuse of code.

ViewModel
The ViewModel class is built for a View. Yes, it can be used by more than one View, but let's not go off on what-ifs and other scenarios quite yet. For now, let's assume we have a ViewModel whose job is to expose the data points and presentation logic that a specific View needs. The TimelineViewModel class has a Tweets property, which is an Observable-Collection<Tweet> that aggregates a collection of instances of the Model class for the View in my sample app.

What's the main job of my ViewModel?

  1. Expose the Models needed by the View (Tweets or IsBusy, for example)
  2. Expose the logic needed by the View (RefreshTweets, for example)
  3. Handle any presentation logic

The ViewModel inherits from Observable-Object (which implements INPC), so all of its properties will let the View know when they change. This example just uses a single Model, but in many cases the ViewModel may aggregate multiple Model classes, which could even be object graphs. The ViewModel is built to handle customizing the exposure of the data for the View. What I mean by this is that the ViewModel can aggregate one or more Model classes and add other properties that the View may need. For example, my View may need to bind to properties such as IsBusy or LoggedInAsName, neither of which are in the Model Tweet. I can simply add these to the ViewModel as needed.

The ViewModel also handles presentation logic. One simple example of this is the job of making the call to go get the latest tweets and loading the Tweets property in the ViewModel. In my sample app I mocked this so it's not actually hitting the Twitter services, but the concept is exactly the same.

OK, quick pro tip: I like my ViewModel classes to direct the data manipulation calls; however, I abstract the calls to a data service, then out to its own class. In this example I would create a class called TwitterService and it would then make the API calls to Twitter. The ViewModel would just call the TwitterService class's GetTweets method. I find this abstraction really nice for three big reasons. First, it hides the Web service API calls from the ViewModel, which really could care less about how it gets its data. Second, the TwitterService class is now reusable by other ViewModel classes. Finally, this is really great for design-time data and for mock data when unit testing.

View
Now we get to the View, the final piece of the MVVM triad. My TimelineView has a ListBox that defines an ItemTemplate for displaying the individual tweets. Timeline-View is databound to the TimelineViewModel declaratively in the XAML. First, the ViewModel is created as a static resource:

<phone:PhoneApplicationPage.Resources>
  <local:TimelineViewModel x:Key="TimelineViewModel" />
</phone:PhoneApplicationPage.Resources>

Then the View is data bound to the ViewModel by setting the DataContext. In the sample app I do this in the outermost panel in the page, which happens to be the Grid:

DataContext="{Binding Source=
  {StaticResource TimelineViewModel}}"

Wrapping Up
When you run the sample app you'll see there are no additional references, no magic code, zilch, nada. Some of you may be asking how to hook up communication from the UI to the ViewModel, commands, behaviors, locators, dependency injection, Inversion of Control containers, messaging and dialogs. These tasks can certainly be done with MVVM. This column focuses on the fundamentals of MVVM. Of course, there are great ways to tackle all of those scenarios. But before we fly, let's walk. And that is Papa's Perspective.

About the Author

John Papa is a Microsoft Regional Director and former Microsoft technical evangelist. Author of 100-plus articles and 10 books, he specializes in professional application development with Windows, HTML5, JavaScript, CSS, Silverlight, Windows Presentation Foundation, C#, .NET and SQL Server. Check out his online training with Pluralsight; find him at johnpapa.net and on Twitter at twitter.com/john_papa.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube