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

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

  • What's New for Python, Java in Visual Studio Code

    Microsoft announced March 2024 updates to its Python and Java extensions for Visual Studio Code, the open source-based, cross-platform code editor that has repeatedly been named the No. 1 tool in major development surveys.

Subscribe on YouTube