Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

January 22, 2011

Populating a DataGrid in a Silverlight Application using MVVM

Filed under: C#,Silverlight,VB.NET @ 7:04 pm

Model View View/Model (MVVM) is an effective pattern for building Silverlight applications. It provides many useful benefits when building business applications with Silverlight.

NOTE: This post is part of a series that starts with this prior post. The example in this post uses the application that is built as part of that series.

MVVM requires breaking your Silverlight application into three pieces:

1) View: The user interface that the user sees and interacts with.

2) Model: The representation of the data used by the application.

3) View/Model: The code that provides the communication between the view and the model. This code massages the model into a format required by the view and handles events from the view to perform processing and interact with the data from the model.

There are many reasons to use MVVM. Bing "Silverlight MVVM" and you will find many good articles/posts on the merits of MVVM. The key reasons often sited are:

  • Provides a separate of concerns between the visual parts of the application (View), the processing (View/Model), and the data (Model).
  • Allows for testing of the View/Model logic without need to execute a user interface.
  • Provides a mechanism for design-time data.

And another reason that is often not mentioned is my teenager’s favorite: Everyone else is doing it. Why would that matter? Many Silverlight samples now use MVVM and many other developers posting on the forums or blogs now use MVVM. So the more you understand MVVM, the easier it may be to find help.

(And I don’t know about you, but I seem to spend a lot of my development time these days hunting down how-to’s for getting Silverlight to perform some challenging client-request feature. I hope some day soon I will get Silverlight to bow down to my every command … but today is not that day.)

So let’s start with one of the simplest MVVM applications that we can.

This example populates a simple DataGrid and produces the same results as this prior post that uses code-behind instead of MVVM.

The basic steps for populating a DataGrid in a Silverlight application using MVVM are:

1) Drag and drop a DataGrid control from the toolbox onto the desired page.

2) Build/generate the business objects that contains the data for the grid.

3) Build the View/Model class, exposing properties to bind to the View.

4) Hook the View to the View/Model.

5) Bind the DataGrid to a View/Model property.

Step 1 is self explanatory. If you are working through the set of blog posts, add the DataGrid to the Students page. Otherwise, add a DataGrid to any page.

Be sure to set the AutoGenerateColumns property to True so it will automatically show your data.

The Silverlight page is called a "View" because it is the user’s view of the application. It is the part of the application that the user sees and interacts with.

Step 2 requires a fundamental decision on how you will get data into your application. The primary choices are:

  • Build an entity class in the Silverlight application that is populated from a WCF service.
  • Generate an entity class in the Silverlight application using WCF RIA services and Entity Framework.
  • Generate an entity class in the Silverlight application using WCF RIA services and your business objects (sometimes called Plain Old CLR Objects or POCOs). See this prior post for more information on using WCF RIA with your business objects.

The details of these approaches is beyond the scope of this post, so this example builds an entity class in the Silverlight application that is populated from code to keep things simple.

Regardless of the approach, the entity class in your Silverlight application (built or generated) that defines the structure of the data is called the "Model" because it models, or represents, the application’s data.

Add a Models folder to your Silverlight project. In that folder, add a Student class.

In C#:

using System;

namespace InStepSM.SL.Models
{
    public class Student
    {
        public String StudentName { get; set; }
        public int StudentId { get; set; }
        public decimal Project1Score { get; set; }
        public decimal Project2Score { get; set; }
        public decimal Project3Score { get; set; }
    }
}

In VB:

Namespace Models
    Public Class Student
        Public Property StudentName As String
        Public Property StudentId As Integer
        Public Property Project1Score As Decimal
        Public Property Project2Score As Decimal
        Public Property Project3Score As Decimal
    End Class
End Namespace

NOTE: The VB code Namespace includes only "Models" because VB automatically prepends the application namespace to any defined namespace in the application. The result is InStepSM.SL.Models in this case, just like the C# code.

This class includes a student’s name, Id, and three scores.

Step 3 requires building a new class that is the View/Model.

Add a ViewModels folder to your Silverlight project. In that folder, add a StudentViewModel class.

Implement INotifyPropertyChanged in the ViewModel class. That ensures that the UI is notified when properties of the View/Model are changed.

NOTE: INotifyPropertyChanged requires the System.ComponentModel namespace.

Add a property that contains the list of students. The View will bind to this property. You can define the property to be a List, but if you instead use an ObservableCollection, changes to the list will be reflected in the user interface.

NOTE: ObservableCollection requires the System.Collections.ObjectModel namespace.

In C#:

using System.Collections.ObjectModel;
using System.ComponentModel;
using InStepSM.SL.Models;

namespace InStepSM.SL.ViewModels
{
    public class StudentViewModel: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private ObservableCollection<Student> _studentList;
        public ObservableCollection<Student> StudentList
        {
            get
            {
                return _studentList;
            }
            set
            {
                if (_studentList != value)
                {
                    _studentList = value;
                    OnPropertyChanged("StudentList");
                }
            }
        }

        public StudentViewModel()
        {
            PopulateStudents();
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)        
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
        }

        public void PopulateStudents()
        {
            var itemList = new ObservableCollection<Student>()
                    {new Student(){StudentName="Frodo Baggins",
                                    Project1Score = 89M,
                                    Project2Score=93M,
                                    Project3Score=88M},
                    new Student(){StudentName="Rosie Cotton",
                                    Project1Score = 97M,
                                    Project2Score=93M,
                                    Project3Score=94M},
                    new Student(){StudentName="Samwise Gamgee",
                                    Project1Score = 83M,
                                    Project2Score=90M,
                                    Project3Score=85M},
                    new Student(){StudentName="Peregrin Took",
                                    Project1Score = 69M,
                                    Project2Score=72M,
                                    Project3Score=75M}};
            StudentList = itemList;
        }

    }
}

In VB:

Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports InStepSM.SL.Models

Namespace ViewModels
    Public Class StudentViewModel
        Implements INotifyPropertyChanged

        Public Event PropertyChanged(ByVal sender As Object,  
         ByVal e As System.ComponentModel.PropertyChangedEventArgs)  _
Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

        Private _studentList As ObservableCollection(Of Student)
        Public Property StudentList As ObservableCollection(Of Student)
            Get
                Return _studentList
            End Get
            Set(ByVal value As ObservableCollection(Of Student))
                If _studentList IsNot value Then
                    _studentList = value
                    OnPropertyChanged("StudentList")
                End If
            End Set
        End Property

        Public Sub New()
            PopulateStudents()
        End Sub

        Protected Sub OnPropertyChanged(ByVal propertyName As String)
            If Not String.IsNullOrEmpty(propertyName) Then
                RaiseEvent PropertyChanged(Me,
                          New PropertyChangedEventArgs(propertyName))
            End If
        End Sub

        Public Sub PopulateStudents()
            Dim itemList = New ObservableCollection(Of Student)() From
                 {New Student() With {.StudentName = "Frodo Baggins",
                                    .Project1Score = 89D,
                                    .Project2Score = 93D,
                                    .Project3Score = 88D},
                 New Student() With {.StudentName = "Rosie Cotton",
                                    .Project1Score = 97D,
                                    .Project2Score = 93D,
                                    .Project3Score = 94D},
                 New Student() With {.StudentName = "Samwise Gamgee",
                                    .Project1Score = 83D,
                                    .Project2Score = 90D,
                                    .Project3Score = 85D},
                 New Student() With {.StudentName = "Peregrin Took",
                                    .Project1Score = 69D,
                                    .Project2Score = 72D,
                                    .Project3Score = 75D}}
            StudentList = itemList
        End Sub

    End Class
End Namespace

Step 4 hooks the View to the View/Model. There are several choices for hooking them together.

  • Option 1: Use the code behind.
    You can use the code behind to create an instance of the View/Model and assign it as the DataContext of the page.

    The plus side of this option is that there is then an easy way to handle events. You can create a standard event procedure in your code behind and use the View/Model instance to call a method in the View/Model to perform the event processing.

    The down side of this approach is that you won’t get the design-time data because the designer does not execute the code behind’s constructor.

    The View’s code behind would look something like this:

In C#:

using System.Windows.Controls;
using System.Windows.Navigation;
using InStepSM.SL.ViewModels;

namespace InStepSM.SL.Views
{
    public partial class Overview : Page
    {
        public StudentViewModel vm { get; set; }

        public Overview()
        {
            InitializeComponent();
            vm = new StudentViewModel();
            this.DataContext = vm;
        }

        private void dataGrid1_SelectionChanged(object sender,
                                SelectionChangedEventArgs e)
        {
            vm.SomeMethod();
        }

    }
}

In VB:

Imports InStepSM.SL.ViewModels

Partial Public Class Overview
    Inherits Page

    Public Property vm As StudentViewModel

    Public Sub New()
        InitializeComponent()
        vm = New StudentViewModel()
        Me.DataContext = vm
    End Sub

    Private Sub dataGrid1_SelectionChanged(ByVal sender As Object, 
       ByVal e As System.Windows.Controls.SelectionChangedEventArgs) _
       Handles dataGrid1.SelectionChanged
        vm.SomeMethod()
    End Sub
End Class

And the xaml for the DataGrid would look something like this:

<sdk:DataGrid AutoGenerateColumns="true"
      ItemsSource="{Binding StudentList}"
      Height="200"
      Name="dataGrid1"
      Width="500"
      SelectionChanged="dataGrid1_SelectionChanged" />

Where sdk is:

xmlns:sdk=http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk

  • Option 2: Define the instance of the View/Model in the xaml.
    This is the most common approach because it minimizes the amount of code required in the code behind and provides for design-time data.

    In this option, the View’s code behind is basically empty:

In C#:

using System.Windows.Controls;
using System.Windows.Navigation;

namespace InStepSM.SL.Views
{
    public partial class Overview : Page
    {
        public Overview()
        {
            InitializeComponent();
        }
    }
}

In VB:

Partial Public Class Overview
    Inherits Page

    Public Sub New()
        InitializeComponent()
    End Sub

End Class

The xaml contains the reference to the View/Model, shown in Red:

<navigation:Page x:Class="InStepSM.SL.Views.Overview"        

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:d="
http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=
                                  System.Windows.Controls.Navigation"
xmlns:vms ="clr-namespace:InStepSM.SL.ViewModels"
xmlns:sdk="
http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
d:DesignWidth="640" d:DesignHeight="480"
Title="Overview Page" >

    <!– Reference the View/Model –>
    <navigation:Page.DataContext>
        <vms:StudentViewModel/>
    </navigation:Page.DataContext>

</navigation:Page>

The above vms namespace line references the namespace for our View/Model. The DataContext lines set the DataContext of the page to the StudentViewModel. When the designer executes this xaml, it creates an instance of the StudentViewModel class, which in turn executes the constructor. So any code in the View/Model’s constructor is executed by the designer.

Step 5 binds the property in the View/Model to the DataGrid in the xaml.

<sdk:DataGrid AutoGenerateColumns="true"
      ItemsSource="{Binding StudentList}"
      Height="200"
      Name="dataGrid1"
      Width="500" />

VoilĂ ! The grid data now appears in the designer:

image

And the resulting application appears as follows:

image

This post provides the very basics of using MVVM in a Silverlight application.

There are several frameworks available for working with MVVM, including MVVMLight. But trying MVVM manually first may help you better understand and leverage MVVM frameworks.

Enjoy!

EDIT 1/23/11: Inserted missing code example.

EDIT 1/25/11: Corrected a few lines that were cut off. Added information on setting the AutoGenerateColumns property of the DataGrid to True.

11 Comments

  1.   sekhar — March 19, 2011 @ 12:19 am    Reply

    this is a good article to start with the basic…
    I am using web service to get the data and bind the datagrid.
    The methodsin the service to pouplate the datagrid needs some parameters .

    so if i implement the service in view model then
    how can i pass the parameters from view to view model to populate the gridview.

  2.   Misi — March 22, 2011 @ 4:38 pm    Reply

    Hi, good article

    Could you tell me how can I bind the dategrid items to the real entity from the database? (not with PopulateStudents() )

    thanks

  3.   DeborahK — March 22, 2011 @ 11:34 pm    Reply

    I have an example here:
    http://msmvps.com/blogs/deborahk/archive/2011/01/30/accessing-data-in-a-silverlight-application-ef.aspx
    Is that what you were asking?

  4.   Misi — March 24, 2011 @ 8:37 am    Reply

    I know how to display data into a datagrid, but i want to do it using the MVVM pattern, like in this example but using a real database => model

    check Laurent B. video from MIX 2010 :
    http://channel9.msdn.com/Blogs/kreekman/TechDays-2010-Understanding-the-Model-View-ViewModel-pattern
    starting from the 9th minute.

    In your StudentViewModel() method you call another method PopulateStudents() witch populates manually your datagrid.
    In Laurent’s example hes method is called MainViewModel() witch uses hes DataService class ( where the GetXXX query is defined).

    So returning to your example, do I have to make a DomainDataSource in my xaml ?

    I don’t want to write this in my view:
    StudentContext dx = new StudentContext ();
    this.MVVMdataGrid.ItemsSource = dx.Students;
    dx.Load(dx.GetStudentsQuery());
    I want to write it in my viewmodel.

  5.   Misi — March 27, 2011 @ 12:26 pm    Reply

    any solutions ?

  6.   DeborahK — March 27, 2011 @ 7:05 pm    Reply

    Misi –

    I don’t understand your question?

    No, you don’t need to make a DomainDataSource and no you don’t have to write that code in your view.

    My example above *is* MVVM. See Step #4 (Option 2) and Step #5. Notice that I create the instance of the ViewModel in the xaml, then use binding.

    Is there a part of the above example that you don’t understand?

  7.   Misi — March 28, 2011 @ 12:22 pm    Reply

    Hi, sorry for being unclear
    In this tutorial : http://msmvps.com/blogs/deborahk/archive/2011/01/30/accessing-data-in-a-silverlight-application-ef.aspx(this example is not using the MVVM pattern!)
    you have a database(InStepSM.dbo), a model(InStepSM.edmx), a domain service class for the Student entity(StudentService.cs) witch generated a method that returns data from the database when it’s called(GetStudentsQuery()).

    Now we need to call this method(GetStudentsQuery) to get data for the DataGrid and I want to call it in the StudentViewModel.cs, not in the Students.xaml.cs
    In that example is showed how

    In the example on this page you populate your database with this data with :public void PopulateStudents()

    It’s like changing “Accessing Data in a Silverlight Application: EF” tutorial to use the MVVM pattern.

  8.   DeborahK — March 30, 2011 @ 12:38 am    Reply

    Hi Misi –

    Check out this post:

    http://msmvps.com/blogs/deborahk/archive/2011/02/06/simple-silverlight-mvvm-base-class.aspx

    It takes the EF example and expands it to MVVM.

    Hope this helps!

  9.   Misi — March 31, 2011 @ 6:41 am    Reply

    yes, that’s what I wanted. THANK YOU ! ! !
    the LoadData() and OnStudentsLoaded() methods

    There’s a small error : Object reference not set to an instance of an object. .. at mf.ViewModels.MFViewModel.onMFLoad(LoadOperation lo)
    (In my project I have MF instead of students)
    The funny thing is that it works, the data displays in my datagrid. And a warning appears :
    “Field ‘…StudentContextInstance’ is never assigned to, and will always have its default value null.”

    I didn’t see this tutorial.
    It’s cool that it has a design-time data. It helps.

  10.   Misi — April 1, 2011 @ 10:47 am    Reply

    yes, that’s what I wanted. THANK YOU ! ! !
    the LoadData() and OnStudentsLoaded() methods

    There’s a small error : Object reference not set to an instance of an object. .. at mf.ViewModels.MFViewModel.onMFLoad(LoadOperation lo)
    (In my project I have MF instead of students)
    The funny thing is that it works, the data displays in my datagrid. And a warning appears :
    “Field ‘…StudentContextInstance’ is never assigned to, and will always have its default value null.”

    I didn’t see this tutorial.
    It’s cool that it has a design-time data. It helps.

RSS feed for comments on this post. TrackBack URI

Leave a comment

© 2022 Deborah's Developer MindScape   Provided by WPMU DEV -The WordPress Experts   Hosted by Microsoft MVPs