Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

May 1, 2011

Silverlight MVVM, WCF RIA Services Simple Sample Application

Filed under: ASP.NET RIA Services,C#,Silverlight @ 5:52 pm

This post provides a simple Silverlight MVVM, WCF RIA Services sample application that is used to demonstrate validation techniques. The sample application is provided in this separate post so it can be readily used with any of the presented validation techniques.

NOTE: This post defines a sample application that is used in the validation scenarios presented in this prior post.

The application is a simple data entry form for entering basic student information.

image

To create this application, follow these steps.

1) Build four projects:

  1. C# or VB Class Library project defining the business layer. (This is NOT a Silverlight class library.)
  2. C# or VB Silverlight Application project. (Be sure to check the Enable WCF RIA Services checkbox.)
  3. C# or VB ASP.NET Web project. (This project is automatically created when creating the Silverlight Application project).
  4. C# or VB Silverlight Class Library project. (For the library functions, such as commanding.)

2) In the first Class Library project (the one that is NOT a Silverlight class library), build a Student business object.

In C#:

using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;

namespace InStepValidationExample.BL
{
    public class Student
    {
        public int Age { get; set; }

        public string Email { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public DateTime? RegistrationDate { get; set; }

        [KeyAttribute]
        public int StudentId { get; set; }

        public DateTime? VaccinationDate { get; set; }

        public bool? VaccinationOptOut { get; set; }

        public static Student Retrieve(int id)
        {
            var student = new Student
            {
                StudentId = id,
                LastName = "Baggins",
                FirstName = "Bilbo",
                Age = 111,
                Email =
testemail@live.com,
                VaccinationOptOut = true,
                RegistrationDate = DateTime.Now
            };
            return student;
        }

        public bool Save()
        {
            // Code that saves the changes to the database;
            Debug.WriteLine("Saving: " + LastName + ", " + FirstName);
            return true;
        }
    }
}

In VB:

TBD

This code defines a set of simple properties for a student. The StudentId property is marked with the KeyAttribute, which defines a unique Id for the entity. This attribute is required for this entity to work with WCF RIA Services.

The Retrieve and Save methods in this example are "fake" methods. You would need to replace the code in these methods with code to retrieve and save the student from a data store such as a database. By using the fake code for this, you can try out the validation techniques  without needing to build or access a database.

3) In the ASP.NET Web application, build a Student Domain Service class.

In C#:

namespace InStepValidationExample.SL.Web
{
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using InStepValidationExample.BL;

    [EnableClientAccess()]
    public class StudentService : DomainService
    {

        public Student GetStudentById(int id)
        {
            return Student.Retrieve(id);
        }

        public void UpdateStudent(Student student)
        {

        }

        protected override bool PersistChangeSet()
        {
            Student changedStudent;
            bool success = true;

            foreach (var item in ChangeSet.ChangeSetEntries)
            {
                if (item.Entity.GetType() == typeof(Student))
                {
                    changedStudent = (Student)item.Entity;
                    success = changedStudent.Save();
                    if (!success)
                        break;
                }
            }
            return success;
        }

    }
}

In VB:

TBD

This code provides the following methods:

  • GetStudentById to get the student from the business layer.
  • UpdateStudent method to enable updating of the student.
  • PersistChangeSet method to parse through the changeSet and save any changed students.

You can add Insert and Delete methods as desired.

4) Build an MVVM base class in the Silverlight project as demonstrated in this prior post.

5) Build a Commanding class in the Silverlight Class Library project as demonstrated in this prior post.

6) Build the ViewModel in the Silverlight Application project.

In C#:

using System;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.Windows.Input;
using InStepValidationExample.BL;
using InStepValidationExample.Library;
using InStepValidationExample.SL.Web;

namespace InStepValidationExample.SL.ViewModels
{
    public class StudentsViewModel : ViewModelBase
    {
        private StudentContext StudentContextInstance;

        private ICommand _CancelCommand;
        public ICommand CancelCommand
        {
            get
            {
                return _CancelCommand;
            }
        }

        private Student _CurrentStudent;
        public Student CurrentStudent
        {
            get
            {
                return _CurrentStudent;
            }
            set
            {
                if (_CurrentStudent != value)
                {
                    _CurrentStudent = value;
                    OnPropertyChanged("CurrentStudent");
                }
            }
        }

        private ICommand _SaveCommand;
        public ICommand SaveCommand
        {
            get
            {
                return _SaveCommand;
            }
        }

        public StudentsViewModel()
        {
            LoadData();
            DefineCommands();
        }

       private void DefineCommands()
       {
         _CancelCommand = new DelegateCommand<Object>
                         (OnCancelCommand);
         _SaveCommand = new DelegateCommand<Object>
                    (OnSaveCommand);
       }

        /// <summary>
        /// Loads the data for the application.
        /// </summary>
        private void LoadData()
        {
            if (IsInDesignModeStatic)
            {
                LoadDesignData();
            }
            else
            {
                // Load the student data asynchronously
                StudentContextInstance = new StudentContext();
                var loadop = StudentContextInstance.Load
                                          (StudentContextInstance.
                                                GetStudentByIdQuery(1),
                                                OnStudentLoaded, null);
            }
        }

        /// <summary>
        /// Loads temporary data for use in the designer.
        /// </summary>
        /// <remarks></remarks>
        private void LoadDesignData()
        {
            //Design mode data
            var student = new Student
            {
                LastName = "Baggins",
                FirstName = "Bilbo",
                Age = 111,
                Email = "testemail@live.com",
                VaccinationOptOut = true,
                RegistrationDate = DateTime.Now
            };

            CurrentStudent = student;
        }

        private void OnCancelCommand(object o)
        {
            StudentContextInstance.RejectChanges();
        }

        private void OnStudentLoaded(LoadOperation lo)
        {
            CurrentStudent =
                StudentContextInstance.Students.FirstOrDefault();
        }

        private void OnSaveCommand(object o)
        {
             StudentContextInstance.SubmitChanges(OnChangesSubmitted,
                                                      null);
        }

        private void OnChangesSubmitted(SubmitOperation so)
        {
             if (so.HasError)
             {
                  so.MarkErrorAsHandled();
             }
        }

    }
}

In VB:

TBD

This code defines two commands: Save and Cancel. It then loads design-time data or at run-time it calls the GetStudentById query to retrieve the student from the business layer.

The OnChangesSubmitted code ensures that any validation errors are correctly marked as handled and don’t cause an unhandled exception in your application (error 4004).

7) Build the View.

<UserControl x:Class="InStepValidationExample.SL.MainPage"
    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"
    d:DesignHeight="300" d:DesignWidth="400" 
xmlns:sdk="
http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
xmlns:vms="clr-namespace:InStepValidationExample.SL.ViewModels">

    <UserControl.DataContext>
        <vms:StudentsViewModel />
    </UserControl.DataContext>
   
    <Grid x:Name="LayoutRoot"
          Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid HorizontalAlignment="Center"
              VerticalAlignment="Top"
              DataContext="{Binding CurrentStudent}"
              Margin="10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <sdk:Label Content="First Name:"
                       Grid.Column="0"
                       Grid.Row="0"
                       HorizontalAlignment="Left"
                       Margin="3"
                       VerticalAlignment="Center" />
            <TextBox Grid.Column="1"
                     Grid.Row="0"
                     Height="23"
                     HorizontalAlignment="Left"
                     Margin="3"
                     Name="firstNameTextBox"
                     Text="{Binding Path=FirstName,
                            Mode=TwoWay,
                            TargetNullValue=”}"
                     VerticalAlignment="Center"
                     Width="130" />
            <sdk:Label Content="Last Name:"
                       Grid.Column="0"
                       Grid.Row="1"
                       HorizontalAlignment="Left"
                       Margin="3"
                       VerticalAlignment="Center" />
            <TextBox Grid.Column="1"
                     Grid.Row="1"
                     Height="23"
                     HorizontalAlignment="Left"
                     Margin="3"
                     Name="lastNameTextBox"
                     Text="{Binding Path=LastName,
                            Mode=TwoWay,
                            TargetNullValue=”}"
                     VerticalAlignment="Center"
                     Width="130" />
            <sdk:Label Content="Email:"
                       Grid.Column="0"
                       Grid.Row="2"
                       HorizontalAlignment="Left"
                       Margin="3"
                       VerticalAlignment="Center" />
            <TextBox Grid.Column="1"
                     Grid.Row="2"
                     Height="23"
                     HorizontalAlignment="Left"
                     Margin="3"
                     Name="emailTextBox"
                     Text="{Binding Path=Email,
                            Mode=TwoWay,
                            TargetNullValue=”}"
                     VerticalAlignment="Center"
                     Width="130" />
            <sdk:Label Content="Age:"
                       Grid.Column="0"
                       Grid.Row="3"
                       HorizontalAlignment="Left"
                       Margin="3"
                       VerticalAlignment="Center" />
            <TextBox Grid.Column="1"
                     Grid.Row="3"
                     Height="23"
                     HorizontalAlignment="Left"
                     TextAlignment="Right"
                     Margin="3"
                     Text="{Binding Path=Age,
                            Mode=TwoWay,
                            TargetNullValue=”}"
                     VerticalAlignment="Center"
                     Width="130" />
            <CheckBox Grid.Column="1"
                      Grid.Row="4"
                      IsChecked="{Binding VaccinationOptOut,
                                Mode=TwoWay,
                                TargetNullValue=false}"
                      Content="Vaccination Opt Out"/>
            <sdk:Label Content="Vaccination Date:"
                       Grid.Column="0"
                       Grid.Row="5"
                       HorizontalAlignment="Left"
                       Margin="3"
                       VerticalAlignment="Center" />
            <sdk:DatePicker Grid.Column="1" 
                        Grid.Row="5" 
                        Height="23" 
                        HorizontalAlignment="Left" 
                        Margin="3" 
                        SelectedDate="{Binding Path=VaccinationDate,
                                        Mode=TwoWay,
                                        TargetNullValue=”}" 
                        VerticalAlignment="Center" 
                        Width="130" />
            <sdk:Label Content="Registration Date:"
                       Grid.Column="0"
                       Grid.Row="6"
                       HorizontalAlignment="Left"
                       Margin="3"
                       VerticalAlignment="Center" />
            <sdk:DatePicker Grid.Column="1"
                        Grid.Row="6"
                        Height="23"
                        HorizontalAlignment="Left"
                        Margin="3"
                        SelectedDate="{Binding Path=RegistrationDate,
                                        Mode=TwoWay,
                                        TargetNullValue=”}"
                        VerticalAlignment="Center"
                        Width="130" />
        </Grid>

        <StackPanel Grid.Row="1"
                    Orientation="Horizontal"
                    HorizontalAlignment="Right">
        <Button x:Name="SaveButton"
                Content="Save"
                Command="{Binding SaveCommand}"
                Width="75"
                Height="24"
                Margin="5"/>
        <Button x:Name="CancelButton"
                Content="Cancel"
                Command="{Binding CancelCommand}"
                Width="75"
                Height="24"
                Margin="5" />
        </StackPanel>
    </Grid>
</UserControl>

When you have the above code in place, you should see the design-time data appear in the designer.

8) Run and ensure the runtime data appears.

The code displays the form as shown at the top of this post. As you edit the data on the form, note that there is no validation in place. You can type "aaa" into the age. You can delete the first or last name. And you can put in "aaa" into the email address.

See the other posts in this series for information on adding the validation.

Enjoy!

7 Comments

  1.   B. Clay Shannon — May 2, 2011 @ 9:58 am    Reply

    Nitpicky I know, but you misspelled “vaccination”

  2.   DeborahK — May 3, 2011 @ 12:48 am    Reply

    Hi Clay –
    Thanks for point it out. I am fixing it now.

  3.   Elora — August 13, 2011 @ 12:37 pm    Reply

    I really neeedd to find this info, thank God!

  4.   Sarath — February 6, 2012 @ 9:21 pm    Reply

    I Need a complete silverlight project using mvvm . buit it should get the data from the database. should not be the hard coded .

    send me too this id: sarathkumarchennai@gmail.com

  5.   DeborahK — April 2, 2012 @ 10:55 am    Reply

    Hi Sarath –

    Just replace the code in the Retrieve method of the student class to access your database.

    Here is an example of using a data access component to access your database:

    http://msmvps.com/blogs/deborahk/archive/2009/07/07/dal-retrieve-a-datatable-using-a-sql-statement.aspx

    Hope this helps.

  6.   mahaboob — May 26, 2014 @ 6:22 am    Reply

    not good

  7.   Raghu — May 26, 2014 @ 6:24 am    Reply

    Hi sir,

    this is very useful to me.thanks a lot.

RSS feed for comments on this post. TrackBack URI

Leave a comment

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