Share via


Exercise 2: Creating a ViewModel Class

In this exercise you'll create a ViewModelBase class that provides core functionality that can be used by one or more ViewModel classes. You'll then derive from ViewModelBase and create a ViewModel class that will be used to retrieve and manipulate customer data used in the MainPage.xaml View.

  1. Locate the file named mvvmInpcPropertyCS.snippet (for C#) or mvvmInpcPropertyVB.snippet (for VB) in the SilverlightCustomerViewer/CodeSnippets folder.
  2. Copy the file for your chosen language to the following location (or use Tools Code Snippets Manager in Visual Studio to import it):

    Language

    Lab Files Location

    C#

    Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets

    Visual Basic

    Documents\Visual Studio 2010\Code Snippets\Visual Basic\My Code Snippets

  3. Note:
    The mvvmInpc snippet will be used to create properties within a ViewModel class later in this lab. It's one of several snippets available in MVVM Light (https://mvvmlight.codeplex.com) and has been modified for use in this lab exercise.
  4. Right-click on the SilverlightCustomerViewer project and select Add New Folder. Give the folder a name of ViewModels.
  5. Add a new class into the ViewModels folder named ViewModelBase and mark it as abstract (C#) or MustInherit (VB).
  6. Implement the INotifyPropertyChanged interface on the class and resolve the namespace.
    Note:
    INotifyPropertyChanged is an important interface in Silverlight used by the data binding engine to notify controls and other objects when a bound property value changes. By implementing INotifyPropertyChanged on the ViewModelBase class you can write the code once and re-use it across multiple ViewModel classes. The interface is located in the System.ComponentModel namespace.
  7. Once the interface has been implemented on the ViewModelBase class, add a method named OnPropertyChanged into ViewModelBase to handle raising the PropertyChanged event from the INotifyPropertyChanged interface.
    Note:
    If you need help with this step please refer to the ViewModelBase class in the lab's Completed folder. Creating an OnPropertyChanged method was covered in the data binding lab.
  8. Add a new public Boolean property into the ViewModelBase class named IsDesignTime.
  9. Add a get block (but no set block) into the property that returns DesignerProperties.IsInDesignTool as the value. Resolve any namespaces as needed.
    Note:
    When using the MVVM pattern and ViewModel classes it's important to know when code is executing in a design-time tool such as Visual Studio or Expression Blend and when it's executing at runtime. When code runs in a design tool network calls will not execute properly and can error out the designer. The IsDesignTime property will be used to detect where code is running to ensure that ViewModel classes execute properly at design-time.
  10. Add a new class into the ViewModels folder named MainPageViewModel that derives from ViewModelBase .
  11. Add the following properties into MainPageViewModel using the mvvmInpc code snippet and resolve any missing namespaces as necessary (type mvvmInpc + tab + tab to use the snippet in C# or mvvminpc + tab to use the snippet in VB):

    Property Name

    Property Type

    Customers

    ObservableCollection of Customer

    CurrentCustomer

    Customer

    StatusMessage

    string

  12. Note:
    If you need help with creating the properties in this step refer to the MainPageViewModel class in the lab's Completed folder.
  13. Within the CurrentCustomer property's set block add code to set the StatusMessage property to empty strings (add the code within the existing "if" statement).
  14. Add another property named ServiceAgent of type ICustomersServiceAgent and resolve the namespace (create it as a standard .NET property).
  15. Add the following methods into MainPageViewModel to handle retrieving, updating and deleting customer objects:
    Note:
    The ObjectState parameter used in the following code is automatically created by the WCF proxy generator when using self-tracking entities in Entity Framework 4. By changing the object state we can easily track whether delete or update operations should occur for a given Customer object.

    C#

    private void GetCustomers() { ServiceAgent.GetCustomers((s, e) => Customers = e.Result); } public void UpdateCustomer() { SaveCustomer(ObjectState.Modified); } public void DeleteCustomer() { SaveCustomer(ObjectState.Deleted); Customers.Remove(CurrentCustomer); CurrentCustomer = null; } private void SaveCustomer(ObjectState state) { CurrentCustomer.ChangeTracker.State = state; ServiceAgent.SaveCustomer(CurrentCustomer, (s, e) => { StatusMessage = (e.Result.Status) ? "Success!" : "Unable to complete operation"; }); }

    Visual Basic

    Private SubGetCustomers() ServiceAgent.GetCustomers(Sub(s, e) Customers =e.Result)End Sub Public SubUpdateCustomer() SaveCustomer(ObjectState.Modified)End Sub Public SubDeleteCustomer() SaveCustomer(ObjectState.Deleted) Customers.Remove(CurrentCustomer) CurrentCustomer= NothingEnd Sub Private SubSaveCustomer(ByValstate AsObjectState) CurrentCustomer.ChangeTracker.State= state ServiceAgent.SaveCustomer(CurrentCustomer, _ Sub(s, e)StatusMessage= _ If(e.Result.Status, "Success!", "Unable to complete operation"))End Sub
  16. Add the following constructors into MainPageViewModel:

    C#

    publicMainPageViewModel() : this(newCustomersServiceAgent()){} publicMainPageViewModel(ICustomersServiceAgentserviceAgent){if (!IsDesignTime){if (serviceAgent != null) ServiceAgent=serviceAgent;GetCustomers();}}

    Visual Basic

    Public Sub New() Me.New(NewCustomersServiceAgent())End Sub Public Sub New(ByValserviceAgentAsICustomersServiceAgent) If NotIsDesignTimeThen IfserviceAgentIsNotNothing Then Me.ServiceAgent=serviceAgent End If GetCustomers() End IfEnd Sub
    Note:
    Error: Note format was corrupted. Title should be bold.ViewModel is instantiated without any parameters. It passes a new instance of the CustomersServiceAgent object to the second constructor which assigns it to the ServiceAgent property when not in design mode (note that instead of hard coding the service agent type it could be injected using a dependency injection framework). The second constructor accepts any object that implements the ICustomersServiceAgent interface allowing mock objects to be passed in for the service agent when testing the ViewModel class. Following this pattern provides a flexible way to work with different types of service agent objects when the application is running as well as when tests need to be executed.
  17. Ensure that the SilverlightCustomerViewer project compiles before proceeding to the next exercise.