Learning Silverlight 4 and RIA in C#

This talk is intended to get you going on Silverlight RIA services. The goals are

  1. Establish working footprint with Visual Studio 2010 and Silverlight 4 on your computer.
  2. Introduce Microsoft Blend 4 Concepts at a very high level such as SketchFlow and working with Visual Studio projects and graphical objects.
  3. Create a Silverlight Business Style Web site and pages
  4. Create RIA services to database and consume them by client.
  5. Usage of basic controls such as Grid.
  6. CRUD operations between client and database.

Prerequisites

Concepts

Create Business Application/Web Site

Initial Footprint Setup
  1. Create Business Silverlight Application
    File->New->Project->Visual C#->Silverlight->Silverlight Business Application named EmpApp.
  2. Build and Run Web App EmpApp.Web. (CTRL-F5).
    -> Notice GUI flow and site name.
Create DAL and RIA Service
Creating ADO Entity Model
  1. (Add Entity Data Model) In Solution Explorer highlight the project EmpApp.Web and if it is not the startup project then make it. Do Add New Item (CTRL-SHIFT-A) –>Visual C# –> Data –> ADO.Net Entity Data Model.
    Make Name AdventureWorks.edmx
    (Click to Embiggen)
    EntityDataModel
  2. Next screen Choose Generate from database and select Next:
    GenerateFromDB
  3. Choose Your Data Connection. Most likely you will use the SQL Server express db so type in when browsing fails
    .\SQLExpress
    .Choose Microsoft SQL Server if prompted. Test out the connection and you should end up like this:
    ChooseDB
  4. Next screen is Choose Database Objects and select Tables->Employee(HumanResources). Select Finish.
    DBObjects
  5. The adventureworks EDMX in the editor comes up and note that you see the Employee table.
  6. Build Solution.
Creating Domain Service

We are creating defacto WCF services, without the pain of every step, in this step to allow us to seemlessly do database operations between our silverlight client and the database. To quote Domain Services:

Domain services are WCF services that encapsulate the business logic of an application. A domain service exposes a set of related operations in the form of a service layer. When you create an instance of a domain service, you specify the data operations that are permitted through the domain service.

  1. In EmpApp.Web add new again (CTRL-SHIFT-A). Select Visual C#->Web->Domain Service Class with the name of CorporateService.cs and click Add.
    DomainServiceClass
  2. In the next screen “Add New Domain Service Class” select the checkboxes of Employee and Enable Editing and select OK.
    Note 1: If Employee is not shown in the Entities listing, you most likely have not built the application.
    Note 2:  Failure to select Enable Editing, on the Emplyee item listing, will show up later in the client app when we try to send back changed data.
    ADNDSC
  3. The CoroprateService.CS file is generated. Note the attribute EnableClientAccess and that our service has a method GetEmployees as well as other CRUD operations.
  4. Rebuild. By doing this step our services will be automatically consumed by our EmpApp project. Note the newly added CorporateContextDataContext in DataSources which can be shown.**Note to see the DataSources folder one has to turn it on by 1) selecting at the project level the project EmpApp2)  then select from the menu bar Data->Show Data Sources (Shift-Alt-D).

    ClientDataContext
    Now we are ready to begin to consume some data!
Working With Xaml  and Assets to create our Client Site
Application STrings
  1. Change the Application name:
    (Solution Explorer) (EmpApp Project) Assets->Resources->ApplicationStrings.resx->Application Name
    to Corporate Records.
  2. While in the ApplicationStrings.resx add new row:
    EmployeesPageTitle with the value Employees and Comment “Added by me!”. This will be our first page we add.
  3. Add a final row EmployeeHeader with the value “Corporate Employees”.
  4. Build
Prepping the Site
  1. Open up MainPage.xaml.
  2. In the XAML, copy the objects with the name of Divider1 and Link2 and paste them before the originals. Change the name to Divider3 and Link3. Change NavigateUri from /About to /Employees and ApplicationStrings.AboutPageTitle to ApplicationStrings.EmployeesPageTitle. It should look like this:
    <Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
        <StackPanel x:Name="LinksStackPanel" Style="{StaticResource LinksStackPanelStyle}">
    
            <HyperlinkButton x:Name="Link1" Style="{StaticResource LinkStyle}"
                            NavigateUri="/Home" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.HomePageTitle, Source={StaticResource ResourceWrapper}}"/>
    
            <Rectangle x:Name="Divider3" Style="{StaticResource DividerStyle}"/>
    
            <HyperlinkButton x:Name="Link4" Style="{StaticResource LinkStyle}"
                            NavigateUri="/Employees" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.EmployeesPageTitle, Source={StaticResource ResourceWrapper}}"/>
    
            <Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>
    
            <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"
                            NavigateUri="/About" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.AboutPageTitle, Source={StaticResource ResourceWrapper}}"/>
    
        </StackPanel>
    </Border>
    Build.
Our First Silverlight Page
  1. Open up the View folder of the EmpApp project. (Add new Item) CTRL-SHIFT-A. Select Silverlight->Silverlight Page. Name it Employees.xaml and select Add.
  2. On the XAML editor drag a Stackpanel between <Grid x:Name=”LayooutRoot”. Edit by hand and specify the attributes Orientation=”Vertical” Margin=”0,20,0,20″.
  3. As a node of the Stackpanel drag a TextBlock. Put this in the attribute: Text=”{Binding ApplicationStrings.EmployeeHeader,  Source={StaticResource ResourceWrapper}}”.
    <Grid x:Name="LayoutRoot">
        <StackPanel Orientation="Vertical" Margin="0,20,0,20">
            <TextBlock Text="{Binding ApplicationStrings.EmployeeHeader,  Source={StaticResource ResourceWrapper}}"/>    
    
        </StackPanel>
    
    </Grid>
  4. Build and verify that the employee link and page works in unison.
GRID LOCK

Now we work with getting the data and displaying it by working with the static grid.

  1. Under the TextBlock drag a DataGrid. Edit and add these two attributes shown:
    <sdk:DataGrid Name="dgEmployees" MaxHeight="200" IsReadOnly="True"/>
  2. Right Click on the edit surface and select View Code (F7).
  3. Above the Employees Constructor create an assignment for the context which is listed in the datasources named _CorpContext and new up an instance on the class;ClientDS
  4. In the Employee Constructor assign the datacontext to the grid. Here is the code:
    public partial class Employees : Page
    {
        EmpApp.Web.CorporateContext _CorpContext = new Web.CorporateContext();
    
        public Employees()
        {
            InitializeComponent();
            dgEmployees.ItemsSource = _CorpContext.Employees;
            _CorpContext.Load( _CorpContext.GetEmployeesQuery() );
    
        }
    
        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo( NavigationEventArgs e ) {}
    }
  5. Build and Run. Verify that the Grid gets the data as it should.
Domain Data Source (Fun with a DDS that doesn’t involve a drill) Declaritive Code)
  1. Comment out all the code in the Employees.xaml.CS file which we created. We are now going to do all of it using the DDS and wired in on the XAML.
  2. On the Employees.xaml drag the DomainDataSource to a place before the grid. If the prefix is my change it to riaControls.
  3. To use the DDS we must bring in the namespace for our data from our web project (the server) as shown below:
    <navigation:Page
               xmlns:domain="clr-namespace:EmpApp.Web"
               xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices"  xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="EmpApp.Views.Employees"
               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"
               d:DesignWidth="640" d:DesignHeight="480"
               Title="Employees Page">
    <Grid x:Name="LayoutRoot">
    
        <StackPanel Orientation="Vertical" Margin="0,20,0,20">
            <TextBlock Text="{Binding ApplicationStrings.EmployeeHeader,  Source={StaticResource ResourceWrapper}}"/>
                <riaControls:DomainDataSource Name="EmployeeDataSource"
                                          LoadSize="20"
                                          QueryName="GetEmployees"
                                          AutoLoad="True"
                                          >
                    <riaControls:DomainDataSource.DomainContext>
                        <domain:CorporateContext />
                    </riaControls:DomainDataSource.DomainContext>
                </riaControls:DomainDataSource>
                <sdk:DataGrid
                ItemsSource="{Binding Data, ElementName=EmployeeDataSource}"
                Name="dgEmployees"
                IsReadOnly="True"
                MaxHeight="200"/>
        </StackPanel>
    </Grid>
    </navigation:Page>

    (Explanation)
    Line 2:   This line brings our namespace EmpApp.Web (as found in the DataSources Folder) to be known on the page.
    Line 16: This will be the name of our datasource for this page only, a local name used in line 26.
    Line 22:  We specify that we want to use EmpApp.Web.CorporateContext context as found in the namespace (see line 2)
    Line 26:  The domain datasource name EmployeeDataSource as specified in 16 will be bound to our grid’s ItemsSource parameter.

  4. Build and run and it shows data but then blows up.SkipException
  5. “The method ‘Skip’ is only supported for sorted input in LINQ to Entities. The method ‘OrderBy’ must be called before the method ‘Skip’.
  6. What has happened is that in our Server code which we let the wizard create for us did not have an Orderby and gave us our data unsorted. The datagrid needs this sorted so we must go back to where GetEmployees live and change the code to this:
    // CorporateService.CS in the EmpApp.Web
    
    public IQueryable<Employee> GetEmployees()
    {
        return this.ObjectContext.Employees.OrderBy( em => em.EmployeeID );
    }
  7. Build and run…now we have parity with the code behind way of linking up the data.
Updating a Record via a DataForm
  1. Drag a Data Pager right after the DataGrid:
    <sdk:DataPager PageSize="10" Source="{Binding Data, ElementName=EmployeeDataSource}"/>
  2. Drag a DataForm and add this plumbing
    <toolkit:DataForm x:Name="dfEmployee"
                        Header="Edit Employee Information"
                        AutoGenerateFields="False"
                        AutoCommit="False"
                        AutoEdit="False"
                        CurrentItem="{Binding SelectedItem, ElementName=dgEmployees}">
    
    <toolkit:DataForm.EditTemplate>
        <DataTemplate>
            <StackPanel>
                <toolkit:DataField Label="Employee ID">
                    <TextBox IsReadOnly="True" Text="{Binding EmployeeID, Mode=OneWay}" />
                </toolkit:DataField>
                <toolkit:DataField Label="Active Directory ID">
                    <TextBox Text="{Binding LoginID, Mode=TwoWay}" />
                </toolkit:DataField>
                <toolkit:DataField Label="S/M/D">
                    <TextBox Text="{Binding MaritalStatus, Mode=TwoWay}" />
                </toolkit:DataField>
                <toolkit:DataField Label="Male/Female">
                    <TextBox Text="{Binding Gender, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                </toolkit:DataField>
                <toolkit:DataField Label="Total Vacation Hours">
                    <TextBox Text="{Binding VacationHours, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                </toolkit:DataField>
                <toolkit:DataField Label="Total Sick Hours">
                    <TextBox Text="{Binding SickLeaveHours, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                </toolkit:DataField>
            </StackPanel>
        </DataTemplate>
    </toolkit:DataForm.EditTemplate>
    
                </toolkit:DataForm>
  3. Put in a submit button after the form and use the property event wizard to create a click event.  You may need to build after the drag. Highlight the button and use the properties wizard to name it btnSubmit, Context (the text) of “Submit” and find the event for Click to create a btnSubmit_Click operation.
  4. In the Submit click code-behind do this
    private void btnSubmit_Click( object sender, RoutedEventArgs e )
    {
        EmployeeDataSource.SubmitChanges();
    
    }
  5. Run and attempt to alter a record.

Links

Forums Silverlight Forums  
  MSDN Visual C# General Forum  
Pattern Understanding the Model-View-ViewModel Pattern  
  MVVM Light Toolkit  
RIA What is .NET RIA Services?  
  Tim HeuerPresented by: Tim Heuer .NET RIA Services Intro  
Share