Tutorial: realizar un paseo por RIA Services

En este tutorial se proporciona información general de muchas de las características de WCF RIA Services. En este tutorial, creará una aplicación de RIA Services que recupera los datos de las tablas de la base de datos de ejemplo OLTP de AdventureWorks. Primero, recuperará los datos especificando LoadOperation. A continuación, recuperará esos datos con el control DomainDataSource. Especificará ordenación, filtrado y paginación para el control de presentación de datos y agregará un control DataForm para presentar una vista detallada de los datos. Aplicará reglas de validación a los campos y permitirá al usuario editar los valores de datos. Restringirá el acceso a una operación de dominio a los usuarios autenticados. Finalmente, definirá la asociación entre dos tablas relacionadas y mostrará los datos relacionados.

Sugerencia:
Para obtener tutoriales más breves con el fin de iniciarse creando una solución de RIA Services más básica, vea Tutorial: crear una solución de RIA Services o Tutorial: utilizar la plantilla de aplicación de negocios de Silverlight.

Requisitos previos

Este tutorial y los demás tutoriales presentados en la documentación de WCF RIA Services requieren la instalación y configuración correctas de varios programas de requisitos previos, como Visual Studio 2010 y Silverlight Developer Runtime y SDK, además de WCF RIA Services y el Kit de herramientas de WCF RIA Services. También requieren la instalación y configuración de SQL Server 2008 R2 Express con Advanced Services, así como la instalación de las bases de datos OLTP y LT de AdventureWorks.

Los temas del nodo Requisitos previos para WCF RIA Services proporcionan instrucciones detalladas para el cumplimiento de cada uno de estos requisitos previos. Siga las instrucciones proporcionadas en ellos antes de realizar este tutorial para asegurarse de encontrar el menor número de problemas posibles al trabajar en estos tutoriales de RIA Services .

Crear y configurar la solución

En esta sección, creará y configurará la solución.

Para crear una nueva aplicación de WCF RIA Services

  1. En Visual Studio 2010, cree un nuevo proyecto de RIA Services seleccionando Archivo, Nuevo y, a continuación, Proyecto.

    Aparece el cuadro de diálogo Nuevo proyecto.

  2. En el recuadro Plantillas instaladas, expanda el nodo Visual C# o Visual Basic y seleccione la categoría Silverlight.

  3. Seleccione la plantilla Aplicación de negocios de Silverlight y asigne a la aplicación el nombre HRApp.

  4. Haga clic en Aceptar.

    Observe la estructura de la solución que se crea:

    • La solución está formada por dos proyectos: un proyecto de cliente de Silverlight denominado HRApp y un proyecto de servidor de aplicación web ASP.NET denominado HRApp.Web.

    • La solución predeterminada contiene muchas características implementadas automáticamente, como navegación, inicio de sesión, cierre de sesión y nuevo registro de usuario.

  5. Compile y ejecute (F5) la aplicación y explore la implementación predeterminada.

  6. Cierre el explorador web.

Para configurar la aplicación

  1. En el Explorador de soluciones, en el proyecto de cliente, abra MainPage.xaml.

  2. En la vista XAML, busque el elemento TextBlock denominado ApplicationNameTextBlock.

    Como se muestra en el marcado siguiente, observe que el nombre de aplicación se recupera de un recurso.

    <TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}" 
                       Text="{Binding ApplicationStrings.ApplicationName, Source={StaticResource ResourceWrapper}}"/>
    
  3. En el Explorador de soluciones, expanda la carpeta Assets y, a continuación, expanda la carpeta Resources.

  4. Abra el archivo ApplicationStrings.resx.

  5. Cambie el recurso ApplicationName a Aplicación de RRHH.

  6. Guarde y cierre el archivo ApplicationStrings.resx.

  7. En el Explorador de soluciones, haga clic con el botón secundario en la carpeta Views, haga clic en Agregar y, a continuación, haga clic en Nuevo elemento.

    Se abrirá el cuadro de diálogo Agregar nuevo elemento.

  8. Seleccione la plantilla Página de Silverlight de la categoría Silverlight de Plantillas instaladas y asígnele el nombre EmployeeList.xaml.

  9. Haga clic en Agregar.

  10. Abra EmployeeList.xaml si no se abre automáticamente.

  11. Agregue el código XAML siguiente entre las etiquetas <Grid>.

    <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
      PageScrollViewerStyle}" >
        <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">
    
            <TextBlock Text="Employee List" Style="{StaticResource HeaderTextStyle}"/>
    
        </StackPanel>
    </ScrollViewer>
    
  12. Guarde el archivo EmployeeList.xaml.

  13. Abra MainPage.xaml.

  14. Agregue un nuevo botón de hipervínculo a la parte superior de la página agregando el código XAML siguiente entre los dos botones de hipervínculo existentes.

    <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" NavigateUri="/EmployeeList" TargetName="ContentFrame" Content="Employee List"/>
    
    <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
    
  15. Ejecute la aplicación y observe el nuevo vínculo Lista de empleados en la esquina superior derecha de la página, entre los vínculos Inicio y Acerca de. Haga clic en él para que se muestre la "Lista de empleados" en el cuerpo de la página.

Mostrar datos

En esta sección, creará un Entity Data Model de ADO.NET para las tablas de la base de datos de ejemplo AdventureWorks. A continuación, creará un servicio de dominio que expone las entidades y muestra esos datos en el proyecto de cliente.

Para agregar un origen de datos

  1. En el Explorador de soluciones, haga clic con el botón secundario en el proyecto HRApp.Web, haga clic en Agregar y, a continuación, haga clic en Nuevo elemento.

    Se abrirá el cuadro de diálogo Agregar nuevo elemento.

  2. En la categoría Datos, seleccione la plantilla Entity Data Model de ADO.NET.

  3. Cambie el nombre a AdventureWorks.edmx y, a continuación, haga clic en Agregar.

    Se abre el Asistente para Entity Data Model.

  4. En la página Elegir contenido de Model, haga clic en Generar desde la base de datos y, a continuación, en Siguiente.

  5. En la página Elegir la conexión de datos, cree una conexión a la base de datos AdventureWorks.

  6. Asigne el nombre AdventureWorks_DataEntities a la configuración de conexión de la entidad y, a continuación, haga clic en Siguiente.

  7. En la página Elija los objetos de base de datos expanda el nodo Tablas.

  8. Agregue marcas de verificación al lado de las tablas Employee, PurchaseOrderDetaily PurchaseOrderHeader.

  9. Asigne el nombre AdventureWorks_DataModel al espacio de nombres del modelo y haga clic en Finalizar.

    Aparece Entity Data Model en el diseñador.

  10. Genere la solución.

Para agregar un objeto de servicio de dominio y consultar los datos

  1. En el Explorador de soluciones, haga clic con el botón secundario en el proyecto HRApp.Web, haga clic en Agregar y, a continuación, haga clic en Nuevo elemento.

    Se abrirá el cuadro de diálogo Agregar nuevo elemento.

  2. En la categoría Web, seleccione la plantilla Clase de servicio de dominio.

  3. Asigne el nombre OrganizationService al nuevo elemento.

  4. Haga clic en Agregar.

  5. En el cuadro de diálogo Agregar nueva clase de servicio de dominio, seleccione Employee, PurchaseOrderDetail y PurchaseOrderHeader en la lista de entidades y, a continuación, seleccione Habilitar edición para cada entidad.

  6. Asegúrese de que las casillas Habilitar acceso de cliente y Generar clases asociadas para metadatos están activadas.

  7. Haga clic en Aceptar.

    Los archivos OrganizationService.cs/vb y OrganizationService.metadata.cs/vb se agregan al proyecto.

  8. Abra el archivo OrganizationService.cs/vb.

    Observe que se han creado los métodos de consulta, inserción, actualización, y eliminación para cada entidad. Siempre se crea un método de consulta para una entidad. Los métodos de inserción, actualización y eliminación se agregaron porque estaba seleccionada la opción Habilitar edición.

  9. Personalice el método de consulta GetEmployees() para devolver empleados ordenados por identificador de empleado reemplazando el código generado por el código siguiente.

    Public Function GetEmployees() As IQueryable(Of Employee)
        Return Me.ObjectContext.Employees.OrderBy(Function(e) e.EmployeeID)
    End Function
    
    public IQueryable<Employee> GetEmployees()
    {
        return this.ObjectContext.Employees.OrderBy(e => e.EmployeeID);
    }
    
  10. Genere la solución.

    Cuando se genera la solución, se generan el contexto de dominio y las entidades en el proyecto de cliente.

  11. Abra EmployeeList.xaml.

  12. En el cuadro de herramientas, arrastre un control DataGrid hasta la Vista de diseño justo a continuación del control TextBlock.

    La acción de arrastrar un control DataGrid hasta la Vista de diseño agrega una referencia al ensamblado System.Windows.Controls.Data y agrega el prefijo sdk al elemento Page.

  13. Cambie los valores predeterminados del control DataGrid quitando las propiedades Height y Width, haciendo que sea de solo lectura, estableciéndolo para generar columnas automáticamente y estableciendo su alto mínimo.

    <sdk:DataGrid AutoGenerateColumns="True" IsReadOnly="True" Name="dataGrid1" MinHeight="100" />
    
  14. Guarde EmployeeList.xaml.

  15. Abra EmployeeList.xaml.cs/vb.

  16. Agregue las instrucciones using o Imports siguientes.

    Imports System.ServiceModel.DomainServices.Client
    
    using HRApp.Web;
    using System.ServiceModel.DomainServices.Client;
    
  17. Cree instancias de la clase OrganizationContext y cargue los datos de empleados agregando el código siguiente a EmployeeList.xaml.cs/vb.

    La clase OrganizationContext se genera automáticamente en el proyecto de cliente basándose en la clase OrganizationService del proyecto de servidor.

    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
    
    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. Ejecute la aplicación.

  19. Haga clic en el vínculo Lista de empleados para ver el control DataGrid.

Para agregar una consulta personalizada

  1. En el proyecto HRApp.Web, abra OrganizationService.cs/vb.

  2. Agregue un nuevo método denominado GetSalariedEmployees agregando el código siguiente al cuerpo de la clase.

    Public Function GetSalariedEmployees() As IQueryable(Of Employee)
        Return Me.ObjectContext.Employees.Where(Function(e) e.SalariedFlag = True).OrderBy(Function(e) e.EmployeeID)
    End Function
    
    public IQueryable<Employee> GetSalariedEmployees()
    {
        return this.ObjectContext.Employees.Where(e => e.SalariedFlag == true).OrderBy(e => e.EmployeeID);
    }
    
  3. Genere la solución.

  4. En el proyecto de cliente, abra EmployeeList.xaml.cs/vb.

  5. En el constructor, reemplace la llamada a GetEmployeesQuery() por una llamada a GetSalariedEmployeesQuery().

    _OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery())
    
    _OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery());
    
  6. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

    Observe que todos los empleados mostrados tienen activado el valor SalariedFlag. Los empleados con identificador de empleado 1, 2 y 4 ya no aparecen en la lista porque no son asalariados.

Para agregar un origen de datos de dominio

  1. Abra EmployeeList.xaml.

  2. En el Cuadro de herramientas, arrastre el control DomainDataSource hasta la Vista de diseño, justo delante del control DataGrid. Puede aparecer DomainDataSource en la parte inferior de la lista de controles.

    Sugerencia:
    Si el control DomainDataSource no está en el Cuadro de herramientas, haga clic con el botón secundario en el Cuadro de herramientas y, a continuación, haga clic en Elegir elementos. En la pestaña Componentes Silverlight active DomainDataSource y haga clic en Aceptar.

    Cuando arrastre el control DomainDataSource hasta la Vista de diseño, se creará una referencia con el prefijo riaControls para el espacio de nombres System.Windows.Controls en el elemento Page. Además, aparecerá un icono de origen de datos en la esquina inferior izquierda de la Vista de diseño.

  3. Para las soluciones de C#, agregue la siguiente declaración de espacio de nombres al archivo XAML.

    xmlns:ds="clr-namespace:HRApp.Web"
    
  4. Para las soluciones de Visual Basic, agregue la siguiente declaración de espacio de nombres al archivo XAML.

    xmlns:ds="clr-namespace:HRApp"
    
  5. Asigne al control DomainDataSource el nombre employeeDataSource y establezca LoadSize, AutoLoad y el método de consulta reemplazando el código XAML existente por el código XAML siguiente.

    <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
    </riaControls:DomainDataSource>
    
  6. Establezca el elemento DomainContext para DomainDataSource agregando el código XAML siguiente.

    <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True">
        <riaControls:DomainDataSource.DomainContext>
            <ds:OrganizationContext/>
        </riaControls:DomainDataSource.DomainContext>
    </riaControls:DomainDataSource>
    
  7. Reemplace el control DataGrid por el código XAML siguiente:

    <sdk:DataGrid AutoGenerateColumns="True" IsReadOnly="True" Name="dataGrid1" MinHeight="100" Height="Auto" ItemsSource="{Binding Data, ElementName=employeeDataSource}" />
    
  8. Abra EmployeeList.xaml.cs/vb.

  9. En el constructor, quite o marque como comentario el código para crear instancias de la instancia de OrganizationContext, la llamada a GetSalariedEmployeesQuery() y el código para establecer la propiedad ItemsSource de control DataGrid.

    Ya no necesita cargar explícitamente los datos, ya que DomainDataSource realizará esta acción automáticamente.

    'Dim _OrganizationContext As New OrganizationContext
    Public Sub New()
        InitializeComponent()
        'Me.dataGrid1.ItemsSource = _OrganizationContext.Employees
        '_OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery())
    
    End Sub
    
    //OrganizationContext _OrganizationContext = new OrganizationContext();
    public EmployeeList()
    {
        InitializeComponent();
        //this.dataGrid1.ItemsSource = _OrganizationContext.Employees;
        //_OrganizationContext.Load(_OrganizationContext.GetSalariedEmployeesQuery());
    }
    
  10. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

    La aplicación funciona igual que antes.

Para agregar ordenación, filtrado y paginación al origen de datos

  1. Abra EmployeeList.xaml.

  2. En DomainDataSource, agregue el elemento SortDescriptors siguiente para especificar cómo se ordenan los datos en el control DataGrid.

    Este código XAML muestra cómo ordenar la columna VacationHours en sentido ascendente.

    <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. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

    Los datos se ordenan por el valor de VacationHours y puede cambiar la dirección de la ordenación haciendo clic en el encabezado de columna.

  4. Abra EmployeeList.xaml.

  5. Para permitir al usuario filtrar los registros que se devuelven proporcionando un valor, agregue el código XAML siguiente delante del control DataGrid.

    El código XAML agrega un control TextBox para que el usuario pueda especificar un valor.

    <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. En el elemento DomainDataSource, agregue un descriptor de filtro que se enlace al control TextBox que agregó en el paso anterior.

    <riaControls:DomainDataSource.FilterDescriptors>
        <riaControls:FilterDescriptor 
             PropertyPath="VacationHours" 
             Operator="IsGreaterThanOrEqualTo"
             IgnoredValue=""
             Value="{Binding ElementName=vacationHoursText, Path=Text}"  >
        </riaControls:FilterDescriptor>
    </riaControls:DomainDataSource.FilterDescriptors>
    
  7. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

  8. En el cuadro de texto Filtro de mínimo de horas de vacaciones, escriba 70.

    Observe que los empleados enumerados tienen un valor de VacationHours mayor o igual que 70.

  9. Abra EmployeeList.xaml.

  10. En el Cuadro de herramientas, arrastre un control DataPager hasta un punto situado justo debajo del control DataGrid.

  11. Establezca el tamaño de página en 5 y establezca el origen como se muestra en el código XAML siguiente.

    <sdk:DataPager PageSize="5" Source="{Binding Data, ElementName=employeeDataSource}" HorizontalAlignment="Left" />
    
  12. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

    Verá solo 5 filas de datos filtrados por página y controles de paginación debajo del control DataGrid.

Crear una vista de detalle/maestra

En esta sección, utilizará el control DataForm del Kit de herramientas de Silverlight para proporcionar una vista detallada de los datos. De forma predeterminada, la plantilla de proyecto Aplicación de negocios de Silverlight contiene el archivo binario System.Windows.Controls.Data.DataForm.Toolkit.dll en la carpeta Libs.

Para agregar un elemento DataForm

  1. Abra EmployeeList.xaml.

  2. Agregue la declaración de espacio de nombres siguiente.

    xmlns:dataForm="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
    
  3. A continuación del control DataPager, agregue el código XAML siguiente para agregar un control DataForm.

    Este código XAML establece los atributos DataForm y especifica las columnas que se van a mostrar.

    <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. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

    El control DataForm muestra detalles del elemento seleccionado en el control DataGrid.

Actualizar la base de datos

Cuando se activa la casilla Habilitar edición en el cuadro de diálogo Nueva clase de servicio de dominio, los métodos se generan en la capa de servicio de dominio para actualizar, insertar y eliminar la entidad. En esta sección, agregará botones de edición a la interfaz de usuario de la lista de empleados para permitir a los usuarios ejecutar estas operaciones.

Para actualizar un registro

  1. Abra el archivo EmployeeList.xaml.

  2. A continuación del control DataForm, agregue el código XAML siguiente para agregar un botón Enviar.

    <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. En el control DomainDataSource, especifique un controlador de eventos para el evento SubmittedChanges.

    <riaControls:DomainDataSource Name="employeeDataSource" LoadSize="20" QueryName="GetSalariedEmployees" AutoLoad="True" SubmittedChanges="employeeDataSource_SubmittedChanges">
    
  4. Abra EmployeeList.xaml.cs/vb.

  5. Agregue el controlador de eventos siguiente para el evento Click del botón.

    El elemento submitButton está deshabilitado para evitar que el usuario vuelva a enviar el cambio cuando la operación se esté procesando.

    Private Sub submitButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        submitButton.IsEnabled = False
        employeeDataSource.SubmitChanges()
    End Sub
    
    private void submitButton_Click(object sender, RoutedEventArgs e)
    {
        submitButton.IsEnabled = false;
        employeeDataSource.SubmitChanges();
    }
    
  6. Agregue un controlador de eventos para el evento SubmittedChanges que compruebe si la operación de envío se ha completado correctamente y habilita 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
    
    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. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

  8. Seleccione un empleado y haga clic en el icono de lápiz situado en la esquina superior derecha del formulario de datos para habilitar la edición.

    Ahora podrá modificar los campos editables.

  9. Introduzca los cambios que desee en los datos de empleados y haga clic en Aceptar.

  10. Haga clic en el botón Enviar para guardar los datos.

    Los cambios se guardan en la base de datos del servidor solo al hacer clic en el botón Submit.

Para agregar métodos personalizados a un servicio de dominio

  1. En el proyecto de servidor HRApp.Web, abra el archivo OrganizationService.cs/vb.

  2. Agregue el método personalizado siguiente denominado ApproveSabbatical.

    Public Sub ApproveSabbatical(ByVal current As Employee)
        Me.ObjectContext.Employees.AttachAsModified(current)
        current.CurrentFlag = False
    End Sub
    
    public void ApproveSabbatical(Employee current)
    {
        // Start custom workflow here
        this.ObjectContext.Employees.AttachAsModified(current);
        current.CurrentFlag = false;
    }
    
  3. Genere la solución.

  4. Abra EmployeeList.xaml.

  5. A continuación del botón Enviar, agregue el código XAML siguiente para agregar un botón Aprobar excedencia.

    <Button x:Name="approveSabbatical" Width="115" Height="23"  Content="Approve Sabbatical"  Margin="4,0,0,0" Click="approveSabbatical_Click"/>
    
  6. Abra EmployeeList.xaml.cs/vb.

  7. Agregue el siguiente controlador de eventos para el evento Click del botón que llama a la operación de dominio Aprobar excedencia.

    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
    
    private void approveSabbatical_Click(object sender, RoutedEventArgs e)
    {
        Employee luckyEmployee = (Employee)(dataGrid1.SelectedItem);
        luckyEmployee.ApproveSabbatical();
        employeeDataSource.SubmitChanges();
    }
    
  8. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

  9. Haga clic en el botón Aprobar excedencia y observe que la casilla CurrentFlag del empleado seleccionado está desactivada.

Validar datos

El control DataForm puede mostrar los errores de validación de la capa de acceso a datos (DAL). Por ejemplo, si especifica un valor no entero en el campo VacationHours, se muestra un error de validación. La siguiente ilustración muestra un ejemplo del comportamiento de validación.

Cuando se activa la casilla Generar clases asociadas para metadatos en el cuadro de diálogo Nueva clase de servicio de dominio, se crea un archivo que contiene los metadatos. En este tutorial, el archivo de metadatos se denomina OrganizationService.metadata.cs/vb. En esta sección, agregará atributos de validación a este archivo. Las reglas de validación se exigirán en los proyectos de cliente y de servidor.

También creará una interfaz de usuario que permita la adición de nuevos registros de empleados a la base de datos. Las reglas de validación que agregó en las secciones anteriores se aplicarán automáticamente en la nueva interfaz de usuario.

Para agregar una validación básica

  1. En el proyecto HRApp.web, abra OrganizationService.metadata.cs/vb.

  2. Agregue los atributos siguientes a las propiedades VacationHours y Gender.

    <Required()> _
    Public Property Gender As String
    
    <Range(0, 70)> _
    Public Property VacationHours As Short
    
    [Required]
    public string Gender { get; set; }
    
    [Range(0, 70)]
    public short VacationHours { get; set; }
    
  3. Genere la solución.

  4. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

  5. Seleccione un empleado y haga clic en el icono de lápiz situado en la esquina superior derecha del formulario de datos para habilitar la edición.

  6. Especifique un valor en el campo Horas de vacaciones que no esté dentro del intervalo válido (0 a 70) y mueva el foco a otro control.

    Verá un error de validación para las horas de vacaciones.

  7. Elimine el valor del campo Sexo y mueva el foco a otro control.

    Verá un error de validación para el sexo.

Para agregar validación personalizada

  1. En el Explorador de soluciones, haga clic con el botón secundario en el proyecto HRApp.Web, haga clic en Agregar y, a continuación, haga clic en Nuevo elemento.

    Se abrirá el cuadro de diálogo Agregar nuevo elemento.

  2. En la categoría Código, seleccione la plantilla Archivo de código.

  3. Asigne al nuevo elemento el nombre OrganizationService.shared.cs u OrganizationService.shared.vb.

    Los archivos terminados con .shared.cs o .shared.vb estarán disponibles en los proyectos de cliente y de servidor. Los archivos compartidos permiten ejecutar la misma regla de validación en ambos proyectos. Después de crear la solución en un paso posterior, busque en la carpeta oculta Generated_Code del cliente y verá el archivo OrganizationService.shared.cs/vb.

  4. Haga clic en Agregar.

  5. Para crear una clase de validación personalizada que compruebe los valores asignados a la propiedad Gender, agregue el código siguiente al archivo compartido.

    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
    
    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. Abra OrganizationService.metadata.cs/vb.

  7. Agregue el atributo de validación personalizada siguiente a la propiedad Gender.

    <Required()> _
    <CustomValidation(GetType(GenderValidator), "IsGenderValid")> _
    Public Property Gender As String
    
    [CustomValidation(typeof(HRApp.Web.GenderValidator), "IsGenderValid")]
    [Required]
    public string Gender { get; set; }
    
  8. Genere la solución.

  9. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

  10. Seleccione un empleado y haga clic en el icono de lápiz situado en la esquina superior derecha del formulario de datos para habilitar la edición.

  11. Especifique un valor en el campo Sexo que no sea M ni F y mueva el foco a otro control.

    Aparecerá el resultado de la validación personalizada.

Agregar nuevos registros

En esta sección, agregará un formulario que permita al usuario crear un nuevo registro en la tabla Employee.

Para agregar un nuevo registro

  1. En el proyecto HRApp, agregue un nuevo elemento.

  2. En la categoría Silverlight, seleccione la plantilla Ventana secundaria de Silverlight.

  3. Asigne al nuevo elemento el nombre EmployeeRegistrationWindow.xaml.

  4. Haga clic en Agregar.

  5. Abra EmployeeRegistrationWindow.xaml.cs/vb.

  6. Si está utilizando C#, agregue la instrucción using siguiente.

    using HRApp.Web;
    
  7. Agregue una propiedad para la nueva entidad Employee que se crea con los valores de usuario.

    Public Property NewEmployee As Employee
    
    public Employee NewEmployee { get; set; }
    
  8. Abra EmployeeRegistrationWindow.xaml.

  9. Agregue la declaración de espacio de nombres siguiente a EmployeeRegistrationWindow.xaml para utilizar el control DataForm en esta ventana.

    xmlns:dataForm="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
    
  10. Agregue el control DataForm siguiente a EmployeeRegistrationWindow.xaml justo delante del botón Cancelar.

    <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. Abra EmployeeRegistrationWindow.xaml.cs/vb.

  12. Agregue el código siguiente para crear una nueva instancia de Employee y controlar la confirmación de la nueva instancia o la cancelación de la inserción.

    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
    
    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. Abra EmployeeList.xaml.

  14. Entre DataPager y DataForm, agregue el código XAML siguiente para crear un botón denominado 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. Abra EmployeeList.xaml.cs/vb.

  16. Agregue el código siguiente para controlar el evento Click del botón y mostrar 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
    
    private void addNewEmployee_Click(object sender, RoutedEventArgs e)
    {
        EmployeeRegistrationWindow addEmp = new EmployeeRegistrationWindow();
        addEmp.Closed += new EventHandler(addEmp_Closed);
        addEmp.Show();
    }
    
  17. Agregue el método siguiente para controlar el evento closed para 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
    
    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. Abra OrganizationService.cs/vb.

  19. Modifique el método InsertEmployee agregando el código siguiente.

    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
    
    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. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

  21. Haga clic en el botón Agregar empleado.

    Se abre EmployeeRegistrationWindow.

  22. Agregue datos en la ventana y active la casilla En nómina.

  23. Haga clic en Aceptar.

  24. Actualice la página y asegúrese de que el nuevo empleado aparezca en el control DataGrid.

Autenticar usuarios

En esta sección, restringirá el acceso al método ApproveSabbatical a solamente los usuarios autenticados.

Para agregar la autenticación

  1. Abra OrganizationService.cs/vb.

  2. Agregue el atributo RequiresAuthentication al método ApproveSabbatical.

    Cuando aplique el atributo RequiresAuthentication a una operación de dominio, deberá asegurarse de que solo los usuarios autenticados pueden llamar a la operación. Si un usuario anónimo hace clic en el botón Aprobar excedencia, no se ejecutará la operación.

    <RequiresAuthentication()> _
    Public Sub ApproveSabbatical(ByVal current As Employee)
        Me.ObjectContext.Employees.AttachAsModified(current)
        current.CurrentFlag = False
    End Sub
    
    [RequiresAuthentication]
    public void ApproveSabbatical(Employee current)
    {
        // Start custom workflow here
        this.ObjectContext.Employees.AttachAsModified(current);
        current.CurrentFlag = false;
    }
    
  3. Abra EmployeeList.xaml.cs/vb.

  4. Agregue las instrucciones using o Imports siguientes.

    Imports System.ServiceModel.DomainServices.Client.ApplicationServices
    Imports HRApp.LoginUI
    
    using System.ServiceModel.DomainServices.Client.ApplicationServices;
    using HRApp.LoginUI;
    
  5. Modifique el método approveSabbatical_Click y agregue un controlador LoggedIn para comprobar si el usuario está autenticado.

    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
    
    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. Ejecute la aplicación y haga clic en el vínculo Lista de empleados.

  7. Seleccione un registro de empleado y haga clic en el botón Aprobar excedencia.

    Será redirigido a la ventana de inicio de sesión.

  8. Haga clic en el vínculo Registrarse.

  9. Complete los campos obligatorios para crear una nueva cuenta.

  10. Haga clic en Aceptar.

    Iniciará sesión con esa cuenta y su nombre aparecerá en una barra situada debajo de los vínculos de navegación.

Mostrar datos relacionados

Con RIA Services puede trabajar fácilmente con datos de tablas relacionadas. En esta sección, agregará una nueva página de Silverlight y mostrará datos de las tablas PurchaseOrderHeader y PurchaseOrderDetail. También podrá personalizar las operaciones de modificación de datos para que los datos relacionados se modifiquen juntos. Para obtener un ejemplo de modificación de los datos de tablas relacionadas mediante una operación de dominio, vea Jerarquías composicionales.

Para mostrar datos de tablas relacionadas

  1. En el proyecto HRApp, haga clic con el botón secundario en la carpeta Views, haga clic en Agregar y, a continuación, haga clic en Nuevo elemento.

  2. Agregue una nueva página de Silverlight denominada PurchaseOrders.xaml.

  3. Abra PurchaseOrders.xaml.

  4. Agregue el código XAML siguiente entre las etiquetas <Grid>.

    <ScrollViewer x:Name="PageScrollViewer" Style="{StaticResource 
      PageScrollViewerStyle}" >
        <StackPanel x:Name="ContentStackPanel" Style="{StaticResource ContentStackPanelStyle}">
    
            <TextBlock Text="Purchase Orders" Style="{StaticResource HeaderTextStyle}"/>
        </StackPanel>
    </ScrollViewer>
    
  5. Abra MainPage.xaml.

  6. A continuación del vínculo EmployeeList, agregue el código XAML siguiente para incluir un vínculo a la página PurchaseOrders.

    <Rectangle x:Name="Divider3" Style="{StaticResource DividerStyle}"/>
    
    <HyperlinkButton x:Name="Link4" Style="{StaticResource LinkStyle}" NavigateUri="/PurchaseOrders" TargetName="ContentFrame" Content="Purchase Orders"/>
    
  7. Abra OrganizationService.metadata.cs/vb.

  8. Agregue los atributos Composition e Include a la propiedad PurchaseOrderDetails en la clase PurchaseOrderHeaderMetadata.

    <Include()> _
    <Composition()> _
    Public Property PurchaseOrderDetails As EntityCollection(Of PurchaseOrderDetail)
    
    [Include]
    [Composition]
    public EntityCollection<PurchaseOrderDetail> PurchaseOrderDetails { get; set; }
    
  9. Abra OrganizationService.cs/vb.

  10. Cambie el método GetPurchaseOrderHeaders para que los registros relacionados en PurchaseOrderDetails también se recuperen con la consulta.

    Public Function GetPurchaseOrderHeaders() As IQueryable(Of PurchaseOrderHeader)
        Return Me.ObjectContext.PurchaseOrderHeaders.Include("PurchaseOrderDetails").OrderBy(Function(p) p.PurchaseOrderID)
    End Function
    
    public IQueryable<PurchaseOrderHeader> GetPurchaseOrderHeaders()
    {
        return this.ObjectContext.PurchaseOrderHeaders.Include("PurchaseOrderDetails").OrderBy(p => p.PurchaseOrderID);
    }
    
  11. Abra PurchaseOrders.xaml.

  12. En el menú Datos, haga clic en Mostrar orígenes de datos para abrir la ventana Orígenes de datos.

  13. Arrastre el nodo PurchaseOrderHeader hasta la superficie de diseño para PurchaseOrders.xaml.

    Aparecerá un control DataGrid con columnas de la tabla PurchaseOrderHeader.

  14. En la ventana Orígenes de datos, expanda el nodo PurchaseOrderHeader.

  15. Arrastre el nodo PurchaseOrderDetails que se encuentra dentro del nodo PurchaseOrderHeader hasta la superficie de diseño situada justo debajo del control DataGrid para PurchaseOrderHeader.

    Aparecerá un control DataGrid con columnas de la tabla PurchaseOrderDetails.

  16. En la vista XAML, busque los controles DataGrid para PurchaseOrderHeader y PurchaseOrderDetails.

  17. Quite la propiedad Width=”400” de cada control DataGrid para rellenar el ancho disponible.

  18. Delante del control DataGrid de PurchaseOrderHeader, agregue el control TextBlock siguiente para etiquetar los datos.

    <TextBlock Text="Order Headers"></TextBlock>
    
  19. Delante del control DataGrid de PurchaseOrderDetails, agregue el control TextBlock siguiente para etiquetar los datos.

    <TextBlock Text="Order Details"></TextBlock>
    
  20. Para limitar el número de registros que se han de recuperar, agregue el descriptor de filtro siguiente al control DomainDataSource.

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

    En el ejemplo siguiente se muestra el código XAML completo para PurchaseOrders.xaml.

    <navigation:Page x:Class="HRApp.Views.PurchaseOrders" 
               xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
               xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
               xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
               xmlns:mc="https://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="https://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. Ejecute la aplicación y haga clic en el vínculo Pedidos de compra.

  22. Seleccione diferentes registros en el control DataGrid de PurchaseOrderHeader.

    Observe que se muestran automáticamente los registros de PurchaseOrderDetail relacionados.

Pasos siguientes

Este tutorial le ha proporcionado un paseo por muchas de las características de RIA Services . Para aprender los detalles de áreas concretas, vea los demás tutoriales de esta documentación.

Vea también

Tareas

Tutorial: mostrar datos en una aplicación de negocios de Silverlight
Tutorial: utilizar el servicio de autenticación con una aplicación de negocios de Silverlight