# Walkthrough: Taking a Tour of Open Ria Services

\[ **This document was written for WCF Services Version 1 Service Pack 2 and might not be up to date** \
&#x20;Please see [Release Notes](https://github.com/OpenRIAServices/OpenRiaServices/releases) or [Changelog](https://github.com/OpenRIAServices/OpenRiaServices/blob/main/Changelog.md) for a list of changes since WCF RIA Services ]

This walkthrough provides you with an overview of many of the features in Open Ria Services. In this walkthrough, you create a Open Ria Services application that retrieves data from tables in the AdventureWorks OLTP sample database. First, you retrieve the data by specifying the LoadOperation. You then retrieve that data with the DomainDataSource control. You specify sorting, filtering, and paging for the data presentation control, and add a DataForm control to present a detailed view of the data. You apply validation rules to the fields and enable the user to edit data values. You restrict access to a domain operation to authenticated users. Finally, you define the association between two related tables and display the related data.

{% hint style="info" %}
**Tip:** For shorter walkthroughs for getting started by creating a more basic Open Ria Services solution, see [Walkthrough: Creating a Open Ria Services Solution](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ee707376\(v=vs.91\).md) or [Walkthrough: Using the Silverlight Business Application Template](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ee707360\(v=vs.91\).md).
{% endhint %}

## Prerequisites

This and the other walkthroughs presented in the Open Ria Services documentation require several prerequisite programs, such as Visual Studio and the Silverlight Developer Runtime and SDK, be installed and configured properly, in addition to Open Ria Services and the Open Ria Services Toolkit. They also require installing and configuring SQL Server 2008 R2 Express with Advanced Services and installing the AdventureWorks OLTP and LT database.

Detailed instructions for the satisfaction of each of these prerequisites are provided by the topics within the [Prerequisites for Open Ria Services](/openriaservices/gg512106.md) node. Follow the instructions provided there before proceeding with this walkthrough to ensure that you encounter as few problems as possible when working through this Open Ria Services walkthroughs.

## Creating and Setting Up the Solution

In this section, you create and set up the solution.

### To create a new Open Ria Services application

1. In Visual Studio, create a new Open Ria Services project by selecting **File**, **New**, and then **Project**.

   The **New Project** dialog box appears.
2. In the **Installed Templates** pane, expand the **Visual Basic** or **Visual C#** node, and select the **Silverlight** category.
3. Select the **Silverlight Business Application** template and name the application HRApp.

   ![RIA\_HRAppStart](/files/-M_An4VgzoItChAMiMtu)
4. Click **OK**.

   Notice the structure of the solution that is created:

   * The solution consists of two projects: a Silverlight client project named HRApp and an ASP.NET Web Application server project named HRApp.Web.
   * The default solution contains many automatically implemented features including navigation, user login and logout, and new user registration.

   ![RIA\_HRAppStructure](/files/-M_An4VhOfJmP8MGYKnV)
5. Build and Run (F5) the application and explore the default implementation.
6. Close your Web browser.

### To set up the application

1. In **Solution Explorer**, in the client project, open MainPage.xaml.
2. In XAML view, find the TextBlock named ApplicationNameTextBlock.

   As shown in the following markup, notice that the application name is retrieved from a resource.

   ```
   <TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}" 
                      Text="{Binding ApplicationStrings.ApplicationName, Source={StaticResource ResourceWrapper}}"/>
   ```
3. In **Solution Explorer**, expand the Assets folder, and then expand the Resources folder.
4. Open the ApplicationStrings.resx file.
5. Change the ApplicationName resource to HR Application.
6. Save and close the ApplicationStrings.resx file.
7. In **Solution Explorer**, right-click the Views folder, click **Add**, and then click **New Item**.

   The **Add New Item** dialog box is displayed.
8. Select the **Silverlight Page** template from the **Silverlight** category of **Installed Templates** and name it EmployeeList.xaml.

   ![RIA\_HRAppAddPage](/files/-M_An4Vi3Z4Ol302t_r1)
9. Click **Add**.
10. Open EmployeeList.xaml if it does not open automatically.
11. Add the following XAML between the \ tags.

    ```
    <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
      PageScrollViewerStyle}" >
        <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">

            <TextBlock Text="Employee List" Style="{StaticResource HeaderTextStyle}"/>

        </StackPanel>
    </ScrollViewer>
    ```
12. Save the EmployeeList.xaml file.
13. Open MainPage.xaml.
14. Add a new hyperlink button to the top of the page by adding the following XAML between the two existing hyperlink buttons.

    ```
    <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" NavigateUri="/EmployeeList" TargetName="ContentFrame" Content="Employee List"/>

    <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
    ```
15. Run the application and notice the new **Employee List** link on the upper right corner of the page, between the **Home** and **About** links. Click on it to display “Employee List” in the body of the page.

    ![RIA\_HRAppPageView](/files/-M_An4VjCwIlDIdAOrjm)

## Displaying Data

In this section, you create an ADO.NET Entity Data Model for tables in the AdventureWorks sample database. Then, you create a domain service that exposes the entities and displays that data in the client project.

### To add a data source

1. In **Solution Explorer**, right-click the **HRApp.Web** project, click **Add**, and then click **New Item**.

   The **Add New Item** dialog box is displayed.
2. In the **Data** category, select the **ADO.NET Entity Data Model** template.

   ![RIA\_HRAppAddEntity](/files/-M_An4Vk6MSO47c3Nvb6)
3. Change the name to AdventureWorks.edmx, and then click **Add**.

   The **Entity Data Model Wizard** opens.
4. On the **Choose Model Contents** page, click **Generate from database**, and then click **Next**.
5. On the **Choose Your Data Connection** page, create a connection to the AdventureWorks database.
6. Name the entity connection settings AdventureWorks\_DataEntities and then click **Next**.
7. On the **Choose Your Database Objects** page, expand the **Tables** node.
8. Add check marks next to the **Employee**, **PurchaseOrderDetail**, and **PurchaseOrderHeader** tables.
9. Name the model namespace AdventureWorks\_DataModel and then click **Finish**.

   The entity data model appears in the designer.
10. Build the solution.

### To add a domain service object and query for data

1. In **Solution Explorer**, right-click the **HRApp.Web** project, click **Add**, and then click **New Item**.

   The **Add New Item** dialog box is displayed.
2. In the **Web** category, select the **Domain Service Class** template.

   ![RIA\_HRAppAddService](/files/-M_An4VlRRM324uFRGEb)
3. Name the new item OrganizationService.
4. Click **Add**.
5. In the **Add New Domain Service Class** dialog box, select **Employee**, **PurchaseOrderDetail**, and **PurchaseOrderHeader** from the Entities list, and then select **Enable editing** for each entity.
6. Ensure that the **Enable client access** and **Generate associated classes for metadata** check boxes are selected.
7. Click **OK**.

   OrganizationService.cs/vb and OrganizationService.metadata.cs/vb files are added to the project.
8. Open the OrganizationService.cs/vb file.

   Notice that query, insert, update, and delete methods have been created for each entity. A query method is always created for an entity. The insert, update, and delete methods were added because **Enable editing** was selected.
9. Customize the GetEmployees() query method to return employees sorted by EmployeeID by replacing the generated code with the following code.

   ```
   Public Function GetEmployees() As IQueryable(Of Employee)
       Return Me.ObjectContext.Employees.OrderBy(Function(e) e.EmployeeID)
   End Function
   ```

   ```csharp
   public IQueryable<Employee> GetEmployees()
   {
       return this.ObjectContext.Employees.OrderBy(e => e.EmployeeID);
   }
   ```
10. Build the solution.

    Building the solution generates the Domain Context and entities in the client project.
11. Open EmployeeList.xaml.
12. From the Toolbox, drag a DataGrid control to Design view just after the TextBlock control.

    Dragging a DataGrid to Design view adds a reference to the System.Windows.Controls.Data assembly and adds the sdk prefix to the Page element.
13. Change the default values for the DataGrid control by removing the Height and Width properties, making it read-only, setting it to automatically generate columns, and setting its minimum height.

    ```
    <sdk:DataGrid AutoGenerateColumns="True" IsReadOnly="True" Name="dataGrid1" MinHeight="100" />
    ```
14. Save EmployeeList.xaml.
15. Open EmployeeList.xaml.cs/vb.
16. Add the following using or Imports statements.

    ```
    Imports OpenRiaServices.Client
    ```

    ```csharp
    using HRApp.Web;
    using OpenRiaServices.Client;
    ```
17. Instantiate the OrganizationContext class and load employee data by adding the following code to EmployeeList.xaml.cs/vb.

    The OrganizationContext class is automatically generated in the client project based on the OrganizationService class in the server project.

    ```
    Partial Public Class EmployeeList
        Inherits Page

        Dim _OrganizationContext As New OrganizationContext
        Public Sub New()
            InitializeComponent()
            Me.dataGrid1.ItemsSource = _OrganizationContext.Employees
            _OrganizationContext.Load(_OrganizationContext.GetEmployeesQuery())
        End Sub

        'Executes when the user navigates to this page.
        Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)

        End Sub
    End Class
    ```

    ```csharp
    public partial class EmployeeList : Page
    {
        OrganizationContext _OrganizationContext = new OrganizationContext();
        public EmployeeList()
        {
            InitializeComponent();
            this.dataGrid1.ItemsSource = _OrganizationContext.Employees;
            _OrganizationContext.Load(_OrganizationContext.GetEmployeesQuery());
        }

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
    }
    ```
18. Run the application.
19. Click the **Employee List** link to see the DataGrid.

    ![RIA\_HRAppDataGrid](/files/-M_An4Vmg3Tgxrxfg5zi)

### To add a custom query

1. In the HRApp.Web project, open OrganizationService.cs/vb.
2. Add a new method named GetSalariedEmployees by adding the following code to the body of the class.

   ```
   Public Function GetSalariedEmployees() As IQueryable(Of Employee)
       Return Me.ObjectContext.Employees.Where(Function(e) e.SalariedFlag = True).OrderBy(Function(e) e.EmployeeID)
   End Function
   ```

   ```csharp
   public IQueryable<Employee> GetSalariedEmployees()
   {
       return this.ObjectContext.Employees.Where(e => e.SalariedFlag == true).OrderBy(e => e.EmployeeID);
   }
   ```
3. Build the solution.
4. In the client project, open EmployeeList.xaml.cs/vb.
5. In the constructor, replace the call to GetEmployeesQuery() with a call to GetSalariedEmployeesQuery().

   ```
   _OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery())
   ```

   ```csharp
   _OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery());
   ```
6. Run the application and click the **Employee List** link.

   Notice that all of the displayed employees have the SalariedFlag value checked. Employees with EmployeeID 1, 2, and 4 no longer appear in the list because they are not salaried.

   ![RIA\_HRAppFilteredDataGrid](/files/-M_An4VnGFb5ypzPafSg)

### To add a domain data source

1. Open EmployeeList.xaml.
2. From the **Toolbox**, drag the DomainDataSource control to Design view, just before the DataGrid. The DomainDataSource might appear at the bottom of the list of controls.

> \[!TIP] If the DomainDataSource control is not in the **Toolbox**, right click in the **Toolbox**, and click **Choose Items**. Under the **Silverlight Components** tab check **DomainDataSource**, and click **OK**.

```
When you drag the DomainDataSource control to Design view, a reference with the prefix riaControls is created for the System.Windows.Controls namespace in the Page element. Also, a data source icon appears in the lower-left corner of Design view.
```

1. For C# solutions, add the following namespace declaration to the XAML file.

   ```
   xmlns:ds="clr-namespace:HRApp.Web"
   ```
2. For Visual Basic solutions, add the following namespace declaration to the XAML file.

   ```
   xmlns:ds="clr-namespace:HRApp"
   ```
3. Name the DomainDataSource control employeeDataSource and set the LoadSize, AutoLoad, and query method by replacing the existing XAML with the following XAML.

   ```
   <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
   </riaControls:DomainDataSource>
   ```
4. Set the DomainContext for the DomainDataSource by adding the following XAML.

   ```
   <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
       <riaControls:DomainDataSource.DomainContext>
           <ds:OrganizationContext/>
       </riaControls:DomainDataSource.DomainContext>
   </riaControls:DomainDataSource>
   ```
5. Replace the DataGrid with the following XAML.

   ```
   <sdk:DataGrid AutoGenerateColumns="True" IsReadOnly="True" Name="dataGrid1" MinHeight="100" Height="Auto" ItemsSource="{Binding Data, ElementName=employeeDataSource}" />
   ```
6. Open EmployeeList.xaml.cs/vb.
7. In the constructor, remove or comment out the code to instantiate the OrganizationContext instance, the call to GetSalariedEmployeesQuery(), and the code to set the DataGrid control’s ItemsSource property.

   You no longer need to explicitly load data, since the DomainDataSource will do this automatically.

   ```
   'Dim _OrganizationContext As New OrganizationContext
   Public Sub New()
       InitializeComponent()
       'Me.dataGrid1.ItemsSource = _OrganizationContext.Employees
       '_OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery())

   End Sub
   ```

   ```csharp
   //OrganizationContext _OrganizationContext = new OrganizationContext();
   public EmployeeList()
   {
       InitializeComponent();
       //this.dataGrid1.ItemsSource = _OrganizationContext.Employees;
       //_OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery());
   }
   ```
8. Run the application and click the **Employee List** link.

   The application works the same as before.

### To add sorting, filtering, and paging to the data source

1. Open EmployeeList.xaml.
2. In the DomainDataSource, add the following SortDescriptors to specify how data is sorted in the DataGrid.

   This XAML shows how to sort the VacationHours column in ascending order.

   ```
   <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
       <riaControls:DomainDataSource.DomainContext>
           <ds:OrganizationContext/>
       </riaControls:DomainDataSource.DomainContext>
       <riaControls:DomainDataSource.SortDescriptors>
           <riaControls:SortDescriptor PropertyPath="VacationHours" Direction="Ascending" />
       </riaControls:DomainDataSource.SortDescriptors>
   </riaControls:DomainDataSource>
   ```
3. Run the application and click the **Employee List** link.

   The data is sorted by VacationHours and you can change the sort direction by clicking the column header.
4. Open EmployeeList.xaml.
5. To enable the user to filter which records are returned by providing a value, add the following XAML before the DataGrid.

   The XAML adds a TextBox control so that the user can input a value.

   ```
   <StackPanel Orientation="Horizontal" 
     HorizontalAlignment="Left">
       <TextBlock VerticalAlignment="Center" 
       Text="Min Vacation Hours Filter" />
       <TextBox x:Name="vacationHoursText" Width="75" 
     FontSize="11" Margin="4" Text="0"/>
   </StackPanel>
   ```
6. In the DomainDataSource, add a filter descriptor that is bound to the TextBox control you added in the previous step.

   ```
   <riaControls:DomainDataSource.FilterDescriptors>
       <riaControls:FilterDescriptor 
            PropertyPath="VacationHours" 
            Operator="IsGreaterThanOrEqualTo"
            IgnoredValue=""
            Value="{Binding ElementName=vacationHoursText, Path=Text}"  />
       </riaControls:FilterDescriptor>
   </riaControls:DomainDataSource.FilterDescriptors>
   ```
7. Run the application and click the **Employee List** link.
8. In the **Min Vacation Hours Filter** text box, type 70.

   Notice that the listed employees have VacationHours greater than or equal to 70.

   ![RIA\_HRAppVacationFilter](/files/-M_An4VoGVudSHRcFsJD)
9. Open EmployeeList.xaml.
10. From the **Toolbox**, drag a DataPager control to just below the DataGrid.
11. Set the page size to 5 and set the source as shown in the following XAML.

    ```
    <sdk:DataPager PageSize="5" Source="{Binding Data, ElementName=employeeDataSource}" HorizontalAlignment="Left" />
    ```
12. Run the application and click the **Employee List** link.

    You see only 5 rows of filtered data per page and pager controls below the DataGrid.

    ![RIA\_HRAppPagedData](/files/-M_An4VpBnNP48TNPYsr)

## Creating a Master/Detail View

In this section, you use the DataForm control from the Silverlight Toolkit to provide a detailed view of the data. By default, the Silverlight Business Application project template contains the System.Windows.Controls.Data.DataForm.Toolkit.dll binary in the Libs folder.

### To add a DataForm

1. Open EmployeeList.xaml.
2. Add the following namespace declaration.

   ```
   xmlns:dataForm="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
   ```
3. After the DataPager control, add the following XAML to add a DataForm control.

   This XAML sets the DataForm attributes and specifies the columns to be displayed.

   ```
   <dataForm:DataForm x:Name="dataForm1" Header="Employee Information"
           AutoGenerateFields="False" HorizontalAlignment="Left"
           AutoEdit="False" AutoCommit="False" Width="400"
           CurrentItem="{Binding SelectedItem, ElementName=dataGrid1}" Margin="0,12,0,0">
       <dataForm:DataForm.EditTemplate>
           <DataTemplate>
               <StackPanel>
                   <dataForm:DataField Label="Employee ID">
                       <TextBox IsReadOnly="True" 
                 Text="{Binding EmployeeID, Mode=OneWay}" />
                   </dataForm:DataField>
                   <dataForm:DataField Label="Login ID">
                       <TextBox Text="{Binding LoginID, Mode=TwoWay}" />
                   </dataForm:DataField>
                   <dataForm:DataField Label="Hire Date">
                       <TextBox Text="{Binding HireDate, Mode=TwoWay}" />
                   </dataForm:DataField>
                   <dataForm:DataField Label="Marital Status">
                       <TextBox Text="{Binding MaritalStatus, Mode=TwoWay}" />
                   </dataForm:DataField>
                   <dataForm:DataField Label="Gender">
                       <TextBox Text="{Binding Gender, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                   </dataForm:DataField>
                   <dataForm:DataField Label="Vacation Hours">
                       <TextBox Text="{Binding VacationHours, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                   </dataForm:DataField>
                   <dataForm:DataField Label="Sick Leave Hours">
                       <TextBox Text="{Binding SickLeaveHours, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                   </dataForm:DataField>
                   <dataForm:DataField Label="Active">
                       <CheckBox IsChecked="{Binding CurrentFlag, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }"  />
                   </dataForm:DataField>
               </StackPanel>
           </DataTemplate>
       </dataForm:DataForm.EditTemplate>
   </dataForm:DataForm>
   ```
4. Run the application and click the **Employee List** link.

   The DataForm displays details of the item selected in the DataGrid.

   ![RIA\_HRAppDataForm](/files/-M_An4VqjvjAwp8KbeYx)

## Updating the Database

When you select the **Enable editing** check box in the **Add New Domain Service Class** dialog box, methods are generated in the domain service layer to update, insert, and delete the entity. In this section, you add edit buttons to the user interface of the employee list to enable users to execute these operations.

### To update a record

1. Open the EmployeeList.xaml file.
2. After the DataForm control, add the following XAML to add a Submit button.

   ```
   <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,12,0,0">
       <Button x:Name="submitButton" Width="75" Height="23"  
           Content="Submit" Margin="4,0,0,0" Click="submitButton_Click"/>
   </StackPanel>
   ```
3. In the DomainDataSource control, specify an event handler for the [SubmittedChanges](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ee707404.md) event.

   ```
   <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True" SubmittedChanges="employeeDataSource_SubmittedChanges">
   ```
4. Open EmployeeList.xaml.cs/vb.
5. Add the following event handler for the button click event.

   The submitButton is disabled to prevent the user from submitting the change again as the operation is being processed.

   ```
   Private Sub submitButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
       submitButton.IsEnabled = False
       employeeDataSource.SubmitChanges()
   End Sub
   ```

   ```csharp
   private void submitButton_Click(object sender, RoutedEventArgs e)
   {
       submitButton.IsEnabled = false;
       employeeDataSource.SubmitChanges();
   }
   ```
6. Add an event handler for the [SubmittedChanges](https://github.com/OpenRIAServices/OpenRiaServices/tree/82784ac86a5b1cdd95b784ccdb3a00baefcaa7de/docs/ee707404.md) event that checks whether the submit operation completed successfully and enables submitButton.

   ```
   Private Sub employeeDataSource_SubmittedChanges(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SubmittedChangesEventArgs)
       If (e.HasError) Then
           MessageBox.Show(String.Format("Changes were not saved: {0}", e.Error.Message))
           e.MarkErrorAsHandled()
       End If
       submitButton.IsEnabled = True
   End Sub
   ```

   ```csharp
   private void employeeDataSource_SubmittedChanges(object sender, SubmittedChangesEventArgs e)
   {
       if (e.HasError)
       {
           MessageBox.Show(string.Format("Changes were not saved: {0}", e.Error.Message));
           e.MarkErrorAsHandled();
       }
       submitButton.IsEnabled = true;
   }
   ```
7. Run the application and click the **Employee List** link.
8. Select an employee and click the pencil icon in the upper-right hand corner of the data form to enable editing.

   You can now modify any editable field.
9. Make changes to the employee data and click **OK**.
10. Click the **Submit** button to save the data.

    Changes are saved to the database on the server only when you click the Submit button.

### To add custom methods to a domain service

1. In the HRApp.Web server project, open OrganizationService.cs/vb. File
2. Add the following custom method named ApproveSabbatical.

   ```
   Public Sub ApproveSabbatical(ByVal current As Employee)
       Me.ObjectContext.Employees.AttachAsModified(current)
       current.CurrentFlag = False
   End Sub
   ```

   ```csharp
   public void ApproveSabbatical(Employee current)
   {
       // Start custom workflow here
       this.ObjectContext.Employees.AttachAsModified(current);
       current.CurrentFlag = false;
   }
   ```
3. Build the solution.
4. Open EmployeeList.xaml.
5. After the Submit button, add the following XAML to add an Approve Sabbatical button.

   ```
   <Button x:Name="approveSabbatical" Width="115" Height="23"  Content="Approve Sabbatical"  Margin="4,0,0,0" Click="approveSabbatical_Click"/>
   ```
6. Open EmployeeList.xaml.cs/vb.
7. Add the following event handler for the button click event that calls the ApproveSabbatical domain operation.

   ```
   Private Sub approveSabbatical_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
       Dim luckyEmployee As Employee
       luckyEmployee = dataGrid1.SelectedItem
       luckyEmployee.ApproveSabbatical()
       employeeDataSource.SubmitChanges()
   End Sub
   ```

   ```csharp
   private void approveSabbatical_Click(object sender, RoutedEventArgs e)
   {
       Employee luckyEmployee = (Employee)(dataGrid1.SelectedItem);
       luckyEmployee.ApproveSabbatical();
       employeeDataSource.SubmitChanges();
   }
   ```
8. Run the application and click the **Employee List** link.
9. Click the **Approve Sabbatical** button and note that the CurrentFlag check box for the selected employee is cleared.

## Validating Data

The DataForm control can show validation errors from the data access layer (DAL). For example, if you enter a non-integer value in the VacationHours field, a validation error is displayed. The following illustration shows an example of the validation behavior.

![RIA\_HRAppValidation](/files/-M_An4Vr38rQToy4N12V)

When you select the **Generate associated classes for metadata** check box in the **New Domain Service Class** dialog box, a file that contains metadata is created. In this walkthrough, the metadata file is named OrganizationService.metadata.cs/vb. In this section, you add validation attributes to this file. The validation rules will be enforced in the client and server projects.

You also create a user interface to allow the addition of new employee records to the database. The validation rules that you added in the previous sections will automatically be applied in the new user interface.

### To add basic validation

1. In the HRApp.web project, open OrganizationService.metadata.cs/vb.
2. Add the following attributes to the Gender and VacationHours properties.

   ```
   <Required()> _
   Public Property Gender As String

   <Range(0, 70)> _
   Public Property VacationHours As Short
   ```

   ```csharp
   [Required]
   public string Gender { get; set; }

   [Range(0, 70)]
   public short VacationHours { get; set; }
   ```
3. Build the solution.
4. Run the application and click the **Employee List** link.
5. Select an employee and click the pencil icon in the upper-right hand corner of the data form to enable editing.
6. Enter a value in the **Vacation Hours** field that is not within the valid range (0-70) and move the focus to another control.

   You see a validation error for vacation hours.

   ![RIA\_HRAppRangeValidation](/files/-M_An4VsxUSz4Bs2Ipj5)
7. Delete the value in the **Gender** field and move the focus to another control.

   You see a validation error for gender.

### To add custom validation

1. In **Solution Explorer**, right-click the HRApp.Web project, click **Add**, and then click **New Item**.

   The **Add New Item** dialog box is displayed.
2. In the **Code** category, select the **Code File** template.
3. Name the new item OrganizationService.shared.cs or OrganizationService.shared.vb.

   Files that end with .shared.cs or .shared.vb are available in both the client and server projects. Shared files enable you to run the same validation rule in both projects. After you build the solution in a later step, look in the hidden Generated\_Code folder on the client, and you will see the OrganizationService.shared.cs/vb file.
4. Click **Add**.
5. To create a customized validation class that verifies the values assigned to the Gender property, add the following code to the shared file.

   ```
   Imports System
   Imports System.ComponentModel.DataAnnotations

   Public Module GenderValidator
       Public Function IsGenderValid(ByVal gender As String, ByVal context As ValidationContext) As ValidationResult
           If gender = "M" OrElse gender = "m" OrElse gender = "F" OrElse gender = "f" Then
               Return ValidationResult.Success
           Else
               Return New ValidationResult("The Gender field only has two valid values 'M'/'F'", New String() {"Gender"})
           End If
       End Function
   End Module
   ```

   ```csharp
   using System;
   using System.ComponentModel.DataAnnotations;

   namespace HRApp.Web
   {
       public static class GenderValidator
       {
           public static ValidationResult IsGenderValid(string gender, ValidationContext context)
           {
               if (gender == "M" || gender == "m" || gender == "F" || gender == "f")
               {
                   return ValidationResult.Success;
               }
               else
               {
                   return new ValidationResult("The Gender field only has two valid values 'M'/'F'", new string[] { "Gender" });
               }
           }
       }
   }
   ```
6. Open OrganizationService.metadata.cs/vb.
7. Add the following custom validation attribute to the Gender property.

   ```
   <Required()> _
   <CustomValidation(GetType(GenderValidator), "IsGenderValid")> _
   Public Property Gender As String
   ```

   ```csharp
   [CustomValidation(typeof(HRApp.Web.GenderValidator), "IsGenderValid")]
   [Required]
   public string Gender { get; set; }
   ```
8. Build the solution.
9. Run the application and click the **Employee List** link.
10. Select an employee and click the pencil icon in the upper-right hand corner of the data form to enable editing.
11. Enter a value in the **Gender** field that is not M or F and move the focus to another control.

    The result of the custom validation appears.

    ![RIA\_HRAppCustomValidation](/files/-M_An4VtAiMQuiHgy7sx)

## Adding New Records

In this section, you add a form that enables the user to create a new record in the Employee table.

### To add a new record

1. In the HRApp project, add a new item.
2. In the **Silverlight** category, select the **Silverlight Child Window** template.
3. Name the new item EmployeeRegistrationWindow\.xaml.

   ![RIA\_HRAppAddChildWindow](/files/-M_An4VvhcS_2If8fGkw)
4. Click **Add**.
5. Open EmployeeRegistrationWindow\.xaml.cs/vb.
6. If you are using C#, add the following using statement.

   ```csharp
   using HRApp.Web;
   ```
7. Add a property for the new Employee entity that is created with the user values.

   ```
   Public Property NewEmployee As Employee
   ```

   ```csharp
   public Employee NewEmployee { get; set; }
   ```
8. Open EmployeeRegistrationWindow\.xaml.
9. Add the following namespace declaration to EmployeeRegistrationWindow\.xaml to use the DataForm control in this window.

   ```
   xmlns:dataForm="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
   ```
10. Add the following DataForm control to EmployeeRegistrationWindow\.xaml just before the Cancel button.

    ```
    <dataForm:DataForm x:Name="addEmployeeDataForm"   AutoGenerateFields="False" AutoCommit="True" AutoEdit="True" CommandButtonsVisibility="None">
        <dataForm:DataForm.EditTemplate>
            <DataTemplate>
                <StackPanel>
                    <dataForm:DataField Label="Login ID">
                        <TextBox Text="{Binding LoginID, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="National ID">
                        <TextBox Text="{Binding NationalIDNumber, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Title">
                        <TextBox Text="{Binding Title, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Marital Status">
                        <TextBox Text="{Binding MaritalStatus, Mode=TwoWay}" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Gender">
                        <TextBox Text="{Binding Gender, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Salaried">
                        <CheckBox IsChecked="{Binding SalariedFlag, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }" />
                    </dataForm:DataField>
                    <dataForm:DataField Label="Active">
                        <CheckBox IsChecked="{Binding CurrentFlag, Mode=TwoWay,NotifyOnValidationError=True,  ValidatesOnExceptions=True }" />
                    </dataForm:DataField>
                </StackPanel>
            </DataTemplate>
        </dataForm:DataForm.EditTemplate>
    </dataForm:DataForm>
    ```
11. Open EmployeeRegistrationWindow\.xaml.cs/vb.
12. Add the following code to create a new Employee instance and handle either committing the new instance or canceling the insertion.

    ```
    Partial Public Class EmployeeRegistrationWindow
        Inherits ChildWindow

        Public Sub New()
            InitializeComponent()
            NewEmployee = New Employee
            addEmployeeDataForm.CurrentItem = NewEmployee
            addEmployeeDataForm.BeginEdit()
        End Sub

        Public Property NewEmployee As Employee

        Private Sub OKButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles OKButton.Click
            Me.addEmployeeDataForm.CommitEdit()
            Me.DialogResult = True
        End Sub

        Private Sub CancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles CancelButton.Click
            NewEmployee = Nothing
            addEmployeeDataForm.CancelEdit()
            Me.DialogResult = False
        End Sub

    End Class
    ```

    ```csharp
    public partial class EmployeeRegistrationWindow : ChildWindow
    {
        public EmployeeRegistrationWindow()
        {
            InitializeComponent();
            NewEmployee = new Employee();
            addEmployeeDataForm.CurrentItem = NewEmployee;
            addEmployeeDataForm.BeginEdit();    
        }

        public Employee NewEmployee { get; set; }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            addEmployeeDataForm.CommitEdit();
            this.DialogResult = true;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            NewEmployee = null;
            addEmployeeDataForm.CancelEdit();
            this.DialogResult = false;
        }
    }
    ```
13. Open EmployeeList.xaml.
14. Between the DataPager and the DataForm, add the following XAML to create a button named addNewEmployee.

    ```
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,12,0,0">
        <Button x:Name="addNewEmployee" Width="90" Height="23"  Content="Add Employee"  Margin="4,0,0,0" Click="addNewEmployee_Click"/>
    </StackPanel>
    ```
15. Open EmployeeList.xaml.cs/vb.
16. Add the following code to handle the button click event and display the EmployeeRegistrationWindow.

    ```
    Private Sub addNewEmployee_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim addEmp As New EmployeeRegistrationWindow()
        AddHandler addEmp.Closed, AddressOf addEmp_Closed
        addEmp.Show()
    End Sub
    ```

    ```csharp
    private void addNewEmployee_Click(object sender, RoutedEventArgs e)
    {
        EmployeeRegistrationWindow addEmp = new EmployeeRegistrationWindow();
        addEmp.Closed += new EventHandler(addEmp_Closed);
        addEmp.Show();
    }
    ```
17. Add the following method to handle the closed event for EmployeeRegistrationWindow.

    ```
    Private Sub addEmp_Closed(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim emp As EmployeeRegistrationWindow = sender
        If Not emp.NewEmployee Is Nothing Then
            Dim _OrganizationContext As OrganizationContext = employeeDataSource.DomainContext
            _OrganizationContext.Employees.Add(emp.NewEmployee)
            employeeDataSource.SubmitChanges()
        End If
    End Sub
    ```

    ```csharp
    void addEmp_Closed(object sender, EventArgs e)
    {
        EmployeeRegistrationWindow emp = (EmployeeRegistrationWindow)sender;
        if (emp.NewEmployee != null)
        {
            OrganizationContext _OrganizationContext = (OrganizationContext)(employeeDataSource.DomainContext);
            _OrganizationContext.Employees.Add(emp.NewEmployee);
            employeeDataSource.SubmitChanges();
        }
    }
    ```
18. Open OrganizationService.cs/vb.
19. Modify the InsertEmployee method by adding the following code.

    ```
    Public Sub InsertEmployee(ByVal employee As Employee)
        employee.HireDate = DateTime.Now
        employee.ModifiedDate = DateTime.Now
        employee.VacationHours = 0
        employee.SickLeaveHours = 0
        employee.rowguid = Guid.NewGuid()
        employee.ContactID = 1001
        employee.BirthDate = New DateTime(1967, 3, 18)

        If ((employee.EntityState = EntityState.Detached) _
                    = False) Then
            Me.ObjectContext.ObjectStateManager.ChangeObjectState(employee, EntityState.Added)
        Else
            Me.ObjectContext.Employees.AddObject(employee)
        End If
    End Sub
    ```

    ```csharp
    public void InsertEmployee(Employee employee)
    {
        employee.HireDate = DateTime.Now;
        employee.ModifiedDate = DateTime.Now;
        employee.VacationHours = 0;
        employee.SickLeaveHours = 0;
        employee.rowguid = Guid.NewGuid();
        employee.ContactID = 1001;
        employee.BirthDate = new DateTime(1967, 3, 18);

        if ((employee.EntityState != EntityState.Detached))
        {
            this.ObjectContext.ObjectStateManager.ChangeObjectState(employee, EntityState.Added);
        }
        else
        {
            this.ObjectContext.Employees.AddObject(employee);
        }
    }
    ```
20. Run the application and click the **Employee List** link.
21. Click the **Add Employee** button.

    The EmployeeRegistrationWindow opens.

    ![RIA\_Employee\_Registration](/files/-M_An4Vwpz9aOthNljo9)
22. Add data in the window and select the **Salaried** check box.
23. Click **OK**.
24. Refresh the page and ensure that the new employee appears in the DataGrid.

## Authenticating Users

In this section, you restrict access to the ApproveSabbatical method to only authenticated users.

### To add authentication

1. Open OrganizationService.cs/vb.
2. Add the RequiresAuthentication attribute to the ApproveSabbatical method.

   When you apply the RequiresAuthentication attribute to a domain operation, you ensure that only authenticated users can call the operation. If an anonymous user clicks the **Approve Sabbatical** button, the operation is not executed.

   ```
   <RequiresAuthentication()> _
   Public Sub ApproveSabbatical(ByVal current As Employee)
       Me.ObjectContext.Employees.AttachAsModified(current)
       current.CurrentFlag = False
   End Sub
   ```

   ```csharp
   [RequiresAuthentication]
   public void ApproveSabbatical(Employee current)
   {
       // Start custom workflow here
       this.ObjectContext.Employees.AttachAsModified(current);
       current.CurrentFlag = false;
   }
   ```
3. Open EmployeeList.xaml.cs/vb.
4. Add the following using or Imports statements.

   ```
   Imports OpenRiaServices.Client.Authentication
   Imports HRApp.LoginUI
   ```

   ```csharp
   using OpenRiaServices.Client.Authentication;
   using HRApp.LoginUI;
   ```
5. Modify the approveSabbatical\_Click method and add a LoggedIn handler to check whether the user is authenticated.

   ```
   Private Sub approveSabbatical_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
       If WebContext.Current.User IsNot Nothing AndAlso WebContext.Current.User.IsAuthenticated Then
           Dim luckyEmployee As Employee = dataGrid1.SelectedItem
           luckyEmployee.ApproveSabbatical()
           employeeDataSource.SubmitChanges()
       Else
           AddHandler WebContext.Current.Authentication.LoggedIn, AddressOf Current_LoginCompleted
           Dim newWindow As New LoginRegistrationWindow
           newWindow.Show()
       End If
   End Sub

   Private Sub Current_LoginCompleted(ByVal sender As Object, ByVal e As AuthenticationEventArgs)
       Dim luckyEmployee As Employee = dataGrid1.SelectedItem
       luckyEmployee.ApproveSabbatical()
       employeeDataSource.SubmitChanges()
       RemoveHandler WebContext.Current.Authentication.LoggedIn, AddressOf Current_LoginCompleted
   End Sub
   ```

   ```csharp
   private void approveSabbatical_Click(object sender, RoutedEventArgs e)
   {
       if (WebContext.Current.User.IsAuthenticated)
       {
           Employee luckyEmployee = (Employee)(dataGrid1.SelectedItem);
           luckyEmployee.ApproveSabbatical();
           employeeDataSource.SubmitChanges();
       }
       else
       {
           WebContext.Current.Authentication.LoggedIn += Authentication_LoggedIn;
           new LoginRegistrationWindow().Show();
       }
   }

   private void Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
   {
       Employee luckyEmployee = (Employee)(dataGrid1.SelectedItem);
       luckyEmployee.ApproveSabbatical();
       employeeDataSource.SubmitChanges();

       WebContext.Current.Authentication.LoggedIn -= Authentication_LoggedIn;
   }
   ```
6. Run the application and click the **Employee List** link.
7. Select an employee record and click the **Approve Sabbatical** button.

   You are redirected to the login window.
8. Click the **Register now** link.
9. Complete the required fields to create a new account.
10. Click **OK**.

    You are logged in with that account and your name appears in a bar below the navigation links.

## Displaying Related Data

With Open Ria Services you can easily work with data from related tables. In this section, you add a new Silverlight Page and display data from the PurchaseOrderHeader and PurchaseOrderDetail tables. You can also customize the data modification operations so the related data is modified together. For an example of modifying the data in related tables through a domain operation, see [Compositional Hierarchies](/openriaservices/ee707348/ee707356/ee707346.md).

### To display data from related tables

1. In the HRApp project, right-click the Views folder, click **Add**, and then click **New Item**.
2. Add a new Silverlight Page named PurchaseOrders.xaml.
3. Open PurchaseOrders.xaml.
4. Add the following XAML between the \ tags.

   ```
   <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
     PageScrollViewerStyle}" >
       <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">

           <TextBlock Text="Purchase Orders" Style="{StaticResource HeaderTextStyle}"/>
       </StackPanel>
   </ScrollViewer>
   ```
5. Open MainPage.xaml.
6. After the EmployeeList link, add the following XAML to include a link to the PurchaseOrders page.

   ```
   <Rectangle x:Name="Divider3" Style="{StaticResource DividerStyle}"/>

   <HyperlinkButton x:Name="Link4" Style="{StaticResource LinkStyle}" NavigateUri="/PurchaseOrders" TargetName="ContentFrame" Content="Purchase Orders"/>
   ```
7. Open OrganizationService.metadata.cs/vb.
8. Add the Include and Composition attributes to the PurchaseOrderDetails property in the PurchaseOrderHeaderMetadata class.

   ```
   <Include()> _
   <Composition()> _
   Public Property PurchaseOrderDetails As EntityCollection(Of PurchaseOrderDetail)
   ```

   ```csharp
   [Include]
   [Composition]
   public EntityCollection<PurchaseOrderDetail> PurchaseOrderDetails { get; set; }
   ```
9. Open OrganizationService.cs/vb.
10. Change the GetPurchaseOrderHeaders method so that the related records in PurchaseOrderDetails are also retrieved with the query.

    ```
    Public Function GetPurchaseOrderHeaders() As IQueryable(Of PurchaseOrderHeader)
        Return Me.ObjectContext.PurchaseOrderHeaders.Include("PurchaseOrderDetails").OrderBy(Function(p) p.PurchaseOrderID)
    End Function
    ```

    ```csharp
    public IQueryable<PurchaseOrderHeader> GetPurchaseOrderHeaders()
    {
        return this.ObjectContext.PurchaseOrderHeaders.Include("PurchaseOrderDetails").OrderBy(p => p.PurchaseOrderID);
    }
    ```
11. Open PurchaseOrders.xaml.
12. On the **Data** menu, click **Show Data Sources** to open the **Data Sources** window.
13. Drag the **PurchaseOrderHeader** node to the design surface for PurchaseOrders.xaml.

    ![RIA\_Order\_Header](/files/-M_An4Vy_xTVLGfEPToX)

    A DataGrid with columns from the PurchaseOrderHeader table appears.
14. In the **Data Sources** window, expand the **PurchaseOrderHeader** node.
15. Drag the **PurchaseOrderDetails** node that is located inside the **PurchaseOrderHeader** node to the design surface just under the DataGrid for PurchaseOrderHeader.

    ![RIA\_Order\_Details](/files/-M_An4Vz680BTQW-FsxR)

    A DataGrid with columns from the PurchaseOrderDetails table appears.
16. In XAML view, find the DataGrid controls for both PurchaseOrderHeader and PurchaseOrderDetails.
17. Remove the Width=”400” property from each DataGrid so that it will fill the available width.
18. Before the PurchaseOrderHeader DataGrid, add the following TextBlock control to label the data.

    ```
    <TextBlock Text="Order Headers"></TextBlock>
    ```
19. Before the PurchaseOrderDetails DataGrid, add the following TextBlock control to label the data.

    ```
    <TextBlock Text="Order Details"></TextBlock>
    ```
20. To limit the number of records that are retrieved, add the following filter descriptor to the DomainDataSource control.

    ```
    <riaControls:DomainDataSource.FilterDescriptors>
        <riaControls:FilterDescriptor PropertyPath="PurchaseOrderID" Operator="IsLessThan" Value="10"></riaControls:FilterDescriptor>
    </riaControls:DomainDataSource.FilterDescriptors>
    ```

    The following shows the complete XAML for PurchaseOrders.xaml.

    ```
    <navigation:Page x:Class="HRApp.Views.PurchaseOrders" 
               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="PurchaseOrders Page" 
               xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices" 
               xmlns:my="clr-namespace:HRApp.Web" 
               xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
        <sdk:Page.Resources>
            <CollectionViewSource x:Key="purchaseOrderHeaderPurchaseOrderDetailsViewSource" Source="{Binding Path=Data.PurchaseOrderDetails, ElementName=purchaseOrderHeaderDomainDataSource}" />
        </sdk:Page.Resources>
        <Grid x:Name="LayoutRoot">
            <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
              PageScrollViewerStyle}" >
                <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">

                    <TextBlock Text="Purchase Orders" Style="{StaticResource HeaderTextStyle}"/>
                    <riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my:PurchaseOrderHeader, CreateList=true}" Height="0" LoadedData="purchaseOrderHeaderDomainDataSource_LoadedData_1" Name="purchaseOrderHeaderDomainDataSource" QueryName="GetPurchaseOrderHeadersQuery" Width="0">
                        <riaControls:DomainDataSource.DomainContext>
                            <my:OrganizationContext />
                        </riaControls:DomainDataSource.DomainContext>
                        <riaControls:DomainDataSource.FilterDescriptors>
                            <riaControls:FilterDescriptor PropertyPath="PurchaseOrderID" Operator="IsLessThan" Value="10"></riaControls:FilterDescriptor>
                        </riaControls:DomainDataSource.FilterDescriptors>
                    </riaControls:DomainDataSource>
                    <TextBlock Text="Order Headers"></TextBlock>
                    <sdk:DataGrid AutoGenerateColumns="False" Height="200" ItemsSource="{Binding ElementName=purchaseOrderHeaderDomainDataSource, Path=Data}" Name="purchaseOrderHeaderDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
                        <sdk:DataGrid.Columns>
                            <sdk:DataGridTextColumn x:Name="employeeIDColumn" Binding="{Binding Path=EmployeeID}" Header="Employee ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="freightColumn" Binding="{Binding Path=Freight}" Header="Freight" Width="SizeToHeader" />
                            <sdk:DataGridTemplateColumn x:Name="modifiedDateColumn" Header="Modified Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=ModifiedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=ModifiedDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTemplateColumn x:Name="orderDateColumn" Header="Order Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=OrderDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=OrderDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="purchaseOrderIDColumn" Binding="{Binding Path=PurchaseOrderID, Mode=OneWay}" Header="Purchase Order ID" IsReadOnly="True" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="revisionNumberColumn" Binding="{Binding Path=RevisionNumber}" Header="Revision Number" Width="SizeToHeader" />
                            <sdk:DataGridTemplateColumn x:Name="shipDateColumn" Header="Ship Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=ShipDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=ShipDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="shipMethodIDColumn" Binding="{Binding Path=ShipMethodID}" Header="Ship Method ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="statusColumn" Binding="{Binding Path=Status}" Header="Status" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="subTotalColumn" Binding="{Binding Path=SubTotal}" Header="Sub Total" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="taxAmtColumn" Binding="{Binding Path=TaxAmt}" Header="Tax Amt" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="totalDueColumn" Binding="{Binding Path=TotalDue}" Header="Total Due" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="vendorIDColumn" Binding="{Binding Path=VendorID}" Header="Vendor ID" Width="SizeToHeader" />
                        </sdk:DataGrid.Columns>
                    </sdk:DataGrid>
                    <TextBlock Text="Order Details"></TextBlock>
                    <sdk:DataGrid AutoGenerateColumns="False" Height="200" ItemsSource="{Binding Source={StaticResource purchaseOrderHeaderPurchaseOrderDetailsViewSource}}" Name="purchaseOrderDetailsDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected">
                        <sdk:DataGrid.Columns>
                            <sdk:DataGridTemplateColumn x:Name="dueDateColumn" Header="Due Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=DueDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=DueDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="lineTotalColumn" Binding="{Binding Path=LineTotal}" Header="Line Total" Width="SizeToHeader" />
                            <sdk:DataGridTemplateColumn x:Name="modifiedDateColumn1" Header="Modified Date" Width="SizeToHeader">
                                <sdk:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <sdk:DatePicker SelectedDate="{Binding Path=ModifiedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellEditingTemplate>
                                <sdk:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=ModifiedDate, StringFormat=\{0:d\}}" />
                                    </DataTemplate>
                                </sdk:DataGridTemplateColumn.CellTemplate>
                            </sdk:DataGridTemplateColumn>
                            <sdk:DataGridTextColumn x:Name="orderQtyColumn" Binding="{Binding Path=OrderQty}" Header="Order Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="productIDColumn" Binding="{Binding Path=ProductID}" Header="Product ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="purchaseOrderDetailIDColumn" Binding="{Binding Path=PurchaseOrderDetailID}" Header="Purchase Order Detail ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="purchaseOrderIDColumn1" Binding="{Binding Path=PurchaseOrderID}" Header="Purchase Order ID" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="receivedQtyColumn" Binding="{Binding Path=ReceivedQty}" Header="Received Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="rejectedQtyColumn" Binding="{Binding Path=RejectedQty}" Header="Rejected Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="stockedQtyColumn" Binding="{Binding Path=StockedQty}" Header="Stocked Qty" Width="SizeToHeader" />
                            <sdk:DataGridTextColumn x:Name="unitPriceColumn" Binding="{Binding Path=UnitPrice}" Header="Unit Price" Width="SizeToHeader" />
                        </sdk:DataGrid.Columns>
                    </sdk:DataGrid>
                </StackPanel>
            </ScrollViewer>
        </Grid>
    </navigation:Page>
    ```
21. Run the application and click the **Purchase Orders** link.
22. Select different records in the PurchaseOrderHeader DataGrid.

    Notice that the related PurchaseOrderDetail records are automatically displayed.

    ![RIA\_Details\_and\_Header](/files/-M_An4W-0pBGoF6XXYbV)

## Next Steps

This walkthrough has given you a tour of many of the features in Open Ria Services. To learn the details of specific areas, see the other walkthroughs in this documentation.

## See Also

#### Tasks

[Walkthrough: Displaying Data in a Silverlight Business Application](/openriaservices/gg602747/ee796239.md)

[Walkthrough: Using Authentication Service with Silverlight Business Application](/openriaservices/ee707361/ee942449.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://openriaservices.gitbook.io/openriaservices/ee707336/ff713719.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
