Page 1 of 1

Dissecting the default MVVM application template Rate Topic: -----

#1 Core  Icon User is offline

  • using System.Linq;
  • member icon

Reputation: 774
  • View blog
  • Posts: 5,097
  • Joined: 08-December 08

Posted 30 March 2011 - 12:38 PM

*
POPULAR

MVVM (Model-View-ViewModel) is a software development pattern that separates the concerns in an application in three separate entities:

  • Model - represents the data entity that can contain business objects or a data link (used to pull data from a service). It is the entity that carries the information in the application itself.
  • View - the visualization layer that displays the information that is represented by a Model. Basically, this is the user interface.
  • ViewModel - this is the link between the Model and the View. It has the purpose to format the data passed by the ViewModel in an acceptable manner so it can be displayed by the View. Additional operations can be performed here, like calling web services to pull additional information.


To illustrate the relationship between these entities, I would reference Scott Hanselman's MVC chart. You might ask - why MVC when I am talking about MVVM?

The reason is that both patterns are very similar with one difference - in MVC the controller "links" the model to the View, while in MVVM the ViewModel is the engine that is able to manipulate and produce new data for a model to be passed to the View.

Take a look at this relationship:
Attached File  Untitled1.png (44.13K)
Number of downloads: 4

The model has a one-way tie to the ViewModel, that can work with one or more Model instances (even with different data). Once the data is processed, it is passed to the View for display. Notice that the View has a two-way relationship with the ViewModel. That's because the data in the View can be changed on the user's side and it needs to be processed once again when that happens.

Once you install the Windows Phone 7 SDK, you will be able to use a project type called Windows Phone Databound Application.

Attached File  Untitled2.png (106.31K)
Number of downloads: 3

This is the type that will have the basic MVVM skeleton built for you in the context of a standard Silverlight application. Create a new databound app project and take a look at the Solution Explorer.

Attached File  Untitled3.png (20.56K)
Number of downloads: 2

Unlike in a standard Silverlight-based application for Windows Phone 7 there is a new folder called ViewModels and another one called SampleData. So what's missing? The Models folder, but given that this is the basic MVVM skeleton, it is assumed that the developer will create the models himself. The View is the application UI that you can see in the visual designer (or if you take a look at the XAML code).

Let's take a look at the View now to see what's there.

Attached File  Untitled4.png (129.14K)
Number of downloads: 1

You can see that there is a ListBox present that has a custom ItemTemplate defined. However, these items are not created directly by the user but are pulled from a ViewModel. To be specific, take a look at d:DataContext in the page declaration:

Attached File  Untitled5.png (2.11K)
Number of downloads: 2

This is the fragment that tells the designer where to get data from at design time only. The DataContext defines the data source for binding in the page, and in this case it is set to MainViewModelSampleData.xaml. It will only be used to show dummy data in Visual Studio (if the visual designer is enabled) or Expression Blend. So what's in that XAML file?

Attached File  Untitled6.png (24.95K)
Number of downloads: 2

Here it is - the reference to the MainViewModel. There is a SampleProperty, which I know nothing about. There is also apparently a collection called Items that is composed of ItemViewModel instances. Remember that both MainViewModel and ItemViewModel were spotted in the ViewModels folder before.

This is the file that contains the dummy data to be used at design time. But given the fact that I have no idea what a MainViewModel/ItemViewModel looks like at this point, it doesn't help much. So let's look at the code then.

public class MainViewModel : INotifyPropertyChanged
{
    public MainViewModel()
    {
        this.Items = new ObservableCollection<ItemViewModel>();
    }

    public ObservableCollection<ItemViewModel> Items { get; private set; }

    private string _sampleProperty = "Sample Runtime Property Value";
    public string SampleProperty
    {
        get
        {
            return _sampleProperty;
        }
        set
        {
            if (value != _sampleProperty)
            {
                _sampleProperty = value;
                NotifyPropertyChanged("SampleProperty");
            }
        }
    }

    public bool IsDataLoaded
    {
        get;
        private set;
    }

    public void LoadData()
    {
        this.Items.Add(new ItemViewModel() 
            { 
                LineOne = "runtime one", 
                LineTwo = "Maecenas praesent accumsan bibendum", 
                LineThree = "Facilisi faucibus habitant" 
            });

        this.Items.Add(new ItemViewModel() 
            { 
                LineOne = "runtime two", 
                LineTwo = "Dictumst eleifend facilisi faucibus", 
                LineThree = "Suscipit torquent ultrices vehicula" 
            });
   
        this.IsDataLoaded = true;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}



First thing to notice is that the class implements INotifyPropertyChanged. This is the interface that, once implemented, will add the PropertyChangedEventHandler to the class.

public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (null != handler)
    {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}



In very basic terms, INotifyPropertyChanged allows the class to be recognized as an auto-rebindable entity. So if a property is changed inside the class and there is a NotifyPropertyChanged call in the setter, whatever element is bound to that property will be updated to show the new value. That brings us to the next part - the SampleProperty:

private string _sampleProperty = "Sample Runtime Property Value";
public string SampleProperty
{
    get
    {
        return _sampleProperty;
    }
    set
    {
        if (value != _sampleProperty)
        {
            _sampleProperty = value;
            NotifyPropertyChanged("SampleProperty");
        }
    }
}



There is really nothing special about the property itself. It is tied to a field and when the getter is invoked, the value of that field is returned. However, the setter makes sure that the property actually changed before setting it. So if the same value as the current one is passed, nothing happens. If the value changes, then the field is set to use the new value and the NotifyPropertyChanged is called (with the property name passed as a parameter) to inform the bound objects that the View should be updated accordingly.

There are additional helper methods present that allow data loading:

public bool IsDataLoaded
{
    get;
    private set;
}

public void LoadData()
{
    this.Items.Add(new ItemViewModel() 
        { 
            LineOne = "runtime one", 
            LineTwo = "Maecenas praesent accumsan bibendum", 
            LineThree = "Facilisi faucibus habitant" 
        });

    this.Items.Add(new ItemViewModel() 
        { 
            LineOne = "runtime two", 
            LineTwo = "Dictumst eleifend facilisi faucibus", 
            LineThree = "Suscipit torquent ultrices vehicula" 
        });

    this.IsDataLoaded = true;
}



The data will be loaded only once - if IsDataLoaded is set to true, then that's going to be it and a manual update will be necessary, but of course these are just some sample example methods that can easily replaced. The purpose of these is to show that even though there is no strict Model defined, the data is still manipulated from within the ViewModel itself.

There is also the Items collection around:

public ObservableCollection<ItemViewModel> Items { get; private set; }


You might be wondering where is the NotifyPropertyChanged call for it? There shouldn't be one - ObservableCollection is a collection that implements INotifyCollectionchanged and INotifyPropertyChanged by default, and if you look at it through reflector, you will see exactly this situation:

Attached File  Untitled7.png (14.94K)
Number of downloads: 2

On item addition and removal, the collection will be automatically re-bound to all elements that depend on it and pull its data. However, one thing to remember about it is this - it will not be re-bound if an item changes its properties (the collection itself remains intact in that case). Each custom class that is owned by the ObservableCollection instance should implement INotifyPropertyChanged, and that's what ItemViewModel does:

public class ItemViewModel : INotifyPropertyChanged
{
    private string _lineOne;
    public string LineOne
    {
        get
        {
            return _lineOne;
        }
        set
        {
            if (value != _lineOne)
            {
                _lineOne = value;
                NotifyPropertyChanged("LineOne");
            }
        }
    }

    private string _lineTwo;
    public string LineTwo
    {
        get
        {
            return _lineTwo;
        }
        set
        {
            if (value != _lineTwo)
            {
                _lineTwo = value;
                NotifyPropertyChanged("LineTwo");
            }
        }
    }

    private string _lineThree;
    public string LineThree
    {
        get
        {
            return _lineThree;
        }
        set
        {
            if (value != _lineThree)
            {
                _lineThree = value;
                NotifyPropertyChanged("LineThree");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}



So in this particular situation, even when an item changes its value, it will be re-bound to its dependents.

Now you are familiar with basic elements used here - two different ViewModel instances, one (MainViewModel) dependent on the data from another (ItemViewModel). Let's see how both of them are used in the application itself.

Open App.xaml.cs and take a look at the MainViewModel initialization code.

Attached File  Untitled8.png (8.23K)
Number of downloads: 2

When the ViewModel property will be requested for the first time, it will be initialized to a new instance of MainViewModel (that contains the item collection). In case it is already initialized, the current instance will always be returned unless it is nullified and reset. But where exactly is it created?

MainPage.xaml is where the ListBox with the data is, so if you look at the code-behind file you can notice this line in the constructor:

DataContext = App.ViewModel;


Now you know that at runtime the DataContext for the page will be set to the MainViewModel instance we looked at above.

Now the binding for the ListBox should make more sense:

Attached File  Untitled9.png (9.28K)
Number of downloads: 3

There is the Items collection bound to ItemsSource and each TextBlock in the DataTemplate is bound to a property for the associated ItemViewModel (that is pulled automatically from the Items collection).

You can remove the DataContext reference in code-behind and set it in XAML. For example, add a static resource with the referenced ViewModel to the page:

<phone:PhoneApplicationPage.Resources>
    <vm:MainViewModel x:Key="MVModel"></vm:MainViewModel>
</phone:PhoneApplicationPage.Resources>


The only thing that needs to be referenced in the page itself is the vm namespace:

xmlns:vm="clr-namespace:WindowsPhoneDataBoundApplication2"


Now, specifically for the ListBox you can set the DataContext to point to the StaticResource:

DataContext="{StaticResource MVModel}"


But once you run the application, nothing happens and all you see is a blank list. In order to avoid that, you need to add a LoadData call in the MainViewModel constructor:

public MainViewModel()
{
    this.Items = new ObservableCollection<ItemViewModel>();
    LoadData();
}


Once the XAML part that initializes the StaticResource is hit, it will automatically load the data and show you a list of items on startup.

Is This A Good Question/Topic? 5
  • +

Replies To: Dissecting the default MVVM application template

#2 smohd  Icon User is offline

  • Critical Section
  • member icon


Reputation: 1820
  • View blog
  • Posts: 4,627
  • Joined: 14-March 10

Posted 02 April 2011 - 03:55 PM

Does this post makes you to disprove my tutorial?
Was This Post Helpful? 0
  • +
  • -

#3 smohd  Icon User is offline

  • Critical Section
  • member icon


Reputation: 1820
  • View blog
  • Posts: 4,627
  • Joined: 14-March 10

Posted 15 April 2011 - 01:02 PM

Good Turorial
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1