Compartir a través de


Enlazar datos a controles (WCF Data Services)

Con Servicios de datos de Microsoft WCF, puede enlazar controles como ComboBox y ListView a una instancia de la clase DataServiceCollection<T>. Esta colección, que hereda de la clase ObservableCollection<T>, contiene los datos de una fuente de Open Data Protocol (OData). Esta clase representa una colección de datos dinámicos que proporciona notificaciones si se agregan o se quitan elementos. Al usar una instancia de DataServiceCollection<T> para el enlace de datos, las bibliotecas de cliente de Servicios de datos de Microsoft WCF administran estos eventos para garantizar que los objetos supervisados por DataServiceContext sigan estando sincronizados con los datos en el elemento de la interfaz de usuario enlazada.

La clase DataServiceCollection<T>(indirectamente) implementa la interfaz INotifyCollectionChanged para avisar al contexto en el momento en el que se agreguen o quiten objetos de la colección. Los objetos de tipo de servicio de datos usados con una clase DataServiceCollection<T> también deben implementar la interfaz INotifyPropertyChanged para avisar a la clase DataServiceCollection<T> en el momento en el que cambien las propiedades de los objetos en la colección de enlaces.

Nota

Al utilizar el cuadro de diálogo Agregar referencia de servicio o la herramientaDataSvcUtil.exe con la opción /dataservicecollection para generar las clases de servicio de datos de cliente, las clases de datos generadas implementan la interfaz INotifyPropertyChanged.Para obtener más información, vea Cómo: Generar manualmente clases del servicio de datos del cliente (WCF Data Services).

Crear la colección de enlaces

Cree una nueva instancia de la clase DataServiceCollection<T> llamando a uno de los métodos de constructor de clase con una instancia DataServiceContext proporcionada y, opcionalmente, una consulta DataServiceQuery<TElement> o LINQ que, cuando se ejecuta, devuelve una instancia IEnumerable<T>. IEnumerable<T> proporciona el origen de objetos para la colección de enlaces, que se materializan de una fuente OData. Para obtener más información, vea Materialización de objetos (WCF Data Services). De manera predeterminada, DataServiceContext realiza automáticamente el seguimiento de los cambios realizados en los objetos enlazados y elementos insertados en la colección. Si necesita realizar el seguimiento de estos cambios manualmente, llame a uno de los métodos de constructor que toma un parámetro trackingMode y especifica un valor del campo None.

En el siguiente ejemplo se muestra cómo crear una instancia de la clase DataServiceCollection<T> basada en un DataServiceContext proporcionado y una DataServiceQuery<TElement> que devuelve todos los clientes con pedidos (en el ejemplo, Orders) relacionados:

' Create a new collection that contains all customers and related orders.
Dim trackedCustomers As DataServiceCollection(Of Customer) = _
        New DataServiceCollection(Of Customer)(context.Customers.Expand("Orders"))
// Create a new collection that contains all customers and related orders.
DataServiceCollection<Customer> trackedCustomers = 
    new DataServiceCollection<Customer>(context.Customers.Expand("Orders"));

Enlazar datos a elementos de Windows Presentation Foundation

Dado que la clase DataServiceCollection<T> se hereda de la clase ObservableCollection<T>, puede enlazar los objetos a un elemento o control en una aplicación Windows Presentation Foundation (WPF) tal como lo haría si usara la clase ObservableCollection<T> para el enlace. Para obtener más información, vea Enlace de datos (Windows Presentation Foundation). Una manera de enlazar los datos del servicio de datos a controles WPF es establecer la propiedad DataContext del elemento para la instancia de la clase DataServiceCollection<T> que contiene el resultado de la consulta. En este caso, usted utiliza la propiedad ItemsSource para establecer el origen del objeto para el control. Utilice la propiedad DisplayMemberPath para especificar qué propiedad mostrar del objeto enlazado. Si está enlazando un elemento a un objeto relacionado que devuelve una propiedad de navegación, incluya la ruta de acceso en el enlace definido para la propiedad ItemsSource. Esta ruta de acceso es relativa al objeto raíz establecido por la propiedad DataContext del control primario. En el siguiente ejemplo se establece la propiedad DataContext de un elemento StackPanel para enlazar el control primario a una clase DataServiceCollection<T> de objetos de cliente:

' Create a LINQ query that returns customers with related orders.
Dim customerQuery = From cust In context.Customers.Expand("Orders") _
                        Where cust.Country = customerCountry _
                        Select cust

    ' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery)

    ' Bind the root StackPanel element to the collection
    ' related object binding paths are defined in the XAML.
Me.LayoutRoot.DataContext = trackedCustomers
' Create a LINQ query that returns customers with related orders.
Dim customerQuery = From cust In context.Customers.Expand("Orders") _
                        Where cust.Country = customerCountry _
                        Select cust

' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customers)(customerQuery, _
        TrackingMode.AutoChangeTracking, "Customers", _
        AddressOf OnMyPropertyChanged, AddressOf OnMyCollectionChanged)

    ' Bind the root StackPanel element to the collection
    ' related object binding paths are defined in the XAML.
    Me.LayoutRoot.DataContext = trackedCustomers
    Me.LayoutRoot.UpdateLayout()
' Create a LINQ query that returns customers with related orders.
Dim customerQuery = From cust In context.Customers.Expand("Orders") _
                        Where cust.Country = customerCountry _
                        Select cust

' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery, _
        TrackingMode.AutoChangeTracking, "Customers", _
        AddressOf OnMyPropertyChanged, AddressOf OnMyCollectionChanged)

' Bind the root StackPanel element to the collection
' related object binding paths are defined in the XAML.
Me.LayoutRoot.DataContext = trackedCustomers
// Create a LINQ query that returns customers with related orders.
var customerQuery = from cust in context.Customers.Expand("Orders")
                    where cust.Country == customerCountry
                    select cust;

// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery, 
    TrackingMode.AutoChangeTracking,"Customers", 
    OnPropertyChanged, OnCollectionChanged);

// Bind the root StackPanel element to the collection;
// related object binding paths are defined in the XAML.
this.LayoutRoot.DataContext = trackedCustomers;
// Create a LINQ query that returns customers with related orders.
var customerQuery = from cust in context.Customers.Expand("Orders")
                    where cust.Country == customerCountry
                    select cust;

// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery);

// Bind the root StackPanel element to the collection;
// related object binding paths are defined in the XAML.
LayoutRoot.DataContext = trackedCustomers;

En el ejemplo siguiente se muestra la definición de enlace XAML de los controles secundarios DataGrid y ComboBox:

<StackPanel Orientation="Vertical" Height="Auto" Name="LayoutRoot" Width="Auto">
    <Label Content="Customer ID" Margin="20,0,0,0" />
    <ComboBox Name="customerIDComboBox" DisplayMemberPath="CustomerID" ItemsSource="{Binding}" 
              IsSynchronizedWithCurrentItem="True" SelectedIndex="0" Height="23" Width="120" 
              HorizontalAlignment="Left" Margin="20,0,0,0" VerticalAlignment="Center" />
    <ListView ItemsSource="{Binding Path=Orders}" Name="ordersDataGrid" Margin="34,46,34,50">
        <ListView.View>
            <GridView AllowsColumnReorder="False" ColumnHeaderToolTip="Line Items">
                <GridViewColumn DisplayMemberBinding="{Binding Path=OrderID, Mode=OneWay}" 
                    Header="Order ID" Width="50"/>
                <GridViewColumn DisplayMemberBinding="{Binding Path=OrderDate, Mode=TwoWay}" 
                    Header="Order Date" Width="50"/>
                <GridViewColumn DisplayMemberBinding="{Binding Path=Freight, Mode=TwoWay}" 
                    Header="Freight Cost" Width="50"/>
            </GridView>
        </ListView.View>
    </ListView>
    <Button Name="saveChangesButton" Content="Save Changes" Click="saveChangesButton_Click" 
            Width="80" Height="30" Margin="450,0,0,0"/>
</StackPanel>

Para obtener más información, vea Cómo: Enlazar datos a los elementos de Windows Presentation Foundation (WCF Data Services).

Cuando una entidad participa en una relación de uno a varios o de varios a varios, la propiedad de navegación para la relación devuelve una colección de objetos relacionados. Cuando usted utiliza el cuadro de diálogo Agregar referencia de servicio o la herramienta DataSvcUtil.exe para generar las clases de servicio de datos de cliente, la propiedad de navegación devuelve una instancia de la clase DataServiceCollection<T>. Esto le permite enlazar objetos relacionados a un control, así como admitir escenarios de enlace de WPF comunes, como el patrón de enlace principal-detalle para entidades relacionadas. En el ejemplo XAML anterior, el código XAML enlaza la clase principal DataServiceCollection<T> al elemento de datos de raíz. El pedido DataGrid se enlaza a la clase DataServiceCollection<T> de pedidos devueltos desde el objeto Customers seleccionado, que se enlaza a su vez al elemento de datos de raíz de Window.

Enlazar datos a controles de Windows Forms

Para enlazar objetos a un control de Windows Form, establezca la propiedad DataSource del control en la instancia de la clase DataServiceCollection<T> que contiene el resultado de la consulta.

Nota

El enlace de datos solo se admite para los controles que realizan escuchas de los eventos de cambio mediante la implementación de las interfaces INotifyPropertyChanged y INotifyCollectionChanged.Cuando un control no admite este tipo de notificación de cambios, los cambios que se realizan en la clase DataServiceCollection<T> subyacente no se reflejan en el control enlazado.

En el siguiente ejemplo DataServiceCollection<T> se enlaza a ComboBox:

' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery)

'Bind the Customers combobox to the collection.
customersComboBox.DisplayMember = "CustomerID"
customersComboBox.DataSource = trackedCustomers
// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery);

//Bind the Customers combobox to the collection.
customersComboBox.DisplayMember = "CustomerID";
customersComboBox.DataSource = trackedCustomers;

Cuando utiliza el cuadro de diálogo Agregar referencia de servicio para generar las clases de servicio de datos de cliente, también se crea un origen de datos de proyecto basado en el DataServiceContext generado. Con este origen de datos, puede crear controles o elementos de la interfaz de usuario que muestren datos del servicio de datos simplemente arrastrando los elementos desde la ventana Orígenes de datos hasta el diseñador. Estos elementos aparecen en la interfaz de usuario de la aplicación y se enlazan al origen de datos. Para obtener más información, vea Cómo: Enlazar datos mediante un origen de datos del proyecto (WCF Data Services).

Enlazar datos paginados

Un servicio de datos se puede configurar para limitar la cantidad de datos consultados que se devuelven en un único mensaje de respuesta. Para obtener más información, vea Configurar el servicio de datos (WCF Data Services). Cuando el servicio de datos está paginando los datos de respuesta, cada respuesta contiene un vínculo que se utiliza para devolver la página siguiente de resultados. Para obtener más información, vea Cargar contenido aplazado (WCF Data Services). En este caso, debe cargar las páginas explícitamente llamando al método Load en la clase DataServiceCollection<T>, especificando el URI obtenido de la propiedad NextLinkUri, como en el siguiente ejemplo:

    ' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery)

    ' Load all pages of the response at once.
While trackedCustomers.Continuation IsNot Nothing
    trackedCustomers.Load( _
            context.Execute(Of Customer)(trackedCustomers.Continuation.NextLinkUri))
End While
// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery);

// Load all pages of the response at once.
while (trackedCustomers.Continuation != null)
{
    trackedCustomers.Load(
        context.Execute<Customer>(trackedCustomers.Continuation.NextLinkUri));
}

Los objetos relacionados se cargan de una manera similar. Para obtener más información, vea Cómo: Enlazar datos a los elementos de Windows Presentation Foundation (WCF Data Services).

Personalizar comportamientos de enlace de datos

La clase DataServiceCollection<T> le permite interceptar los eventos que se provocan al realizar cambios en la colección (como agregar o quitar un objeto) o en las propiedades de objeto en una colección. Puede modificar los eventos de enlace de datos para reemplazar el comportamiento predeterminado, que incluye las siguientes restricciones:

  • No se realiza ninguna validación dentro de los delegados.

  • Al agregar una entidad, se agregan automáticamente las entidades relacionadas.

  • Al eliminar una entidad, no se eliminan las entidades relacionadas.

Al crear una nueva instancia de DataServiceCollection<T>, tiene la opción de especificar los siguientes parámetros, que definen los delegados para los métodos que administran los eventos provocados cuando se cambian los objetos enlazados:

Nota

Servicios de datos de Microsoft WCF no realiza ninguna validación de los comportamientos personalizados que implementa el usuario en estos delegados.

En el siguiente ejemplo, la acción Remove está personalizada para llamar al método DeleteObject y DeleteLink con el fin de quitar las entidades Orders_Details que pertenecen a una entidad Orders eliminada. Esta acción personalizada se realiza porque las entidades dependientes no se eliminan automáticamente cuando se elimina la entidad primaria.

' Method that is called when the CollectionChanged event is handled.
Private Function OnMyCollectionChanged( _
    ByVal entityCollectionChangedinfo As EntityCollectionChangedParams) As Boolean
    If entityCollectionChangedinfo.Action = _
        NotifyCollectionChangedAction.Remove Then

        ' Delete the related items when an order is deleted.
        If entityCollectionChangedinfo.TargetEntity.GetType() Is GetType(Orders) Then

            ' Get the context and object from the supplied parameter.
            Dim context = entityCollectionChangedinfo.Context
            Dim deletedOrder As Orders = _
            CType(entityCollectionChangedinfo.TargetEntity, Orders)

            ' Load the related OrderDetails.
            context.LoadProperty(deletedOrder, "Order_Details")

            ' Delete the order and its related items
            For Each item As Order_Details In deletedOrder.Order_Details
                'context.DeleteLink(deletedOrder, "Order_Details", item)
                context.DeleteObject(item)
            Next

            ' Delete the order and then return false since the object is already deleted.
            context.DeleteObject(deletedOrder)

            Return False
        Else
            Return True
        End If
    Else
        ' Use the default behavior.
        Return True
    End If
End Function
' Method that is called when the CollectionChanged event is handled.
Private Function OnMyCollectionChanged( _
    ByVal entityCollectionChangedinfo As EntityCollectionChangedParams) As Boolean
    If entityCollectionChangedinfo.Action = _
        NotifyCollectionChangedAction.Remove Then

        ' Delete the related items when an order is deleted.
        If entityCollectionChangedinfo.TargetEntity.GetType() Is GetType(Order) Then

            ' Get the context and object from the supplied parameter.
            Dim context = entityCollectionChangedinfo.Context
            Dim deletedOrder As Order = _
            CType(entityCollectionChangedinfo.TargetEntity, Order)

            If deletedOrder.Order_Details.Count = 0 Then
                ' Load the related OrderDetails.
                context.LoadProperty(deletedOrder, "Order_Details")
            End If

            ' Delete the order and its related items
            For Each item As Order_Detail In deletedOrder.Order_Details
                context.DeleteObject(item)
            Next

            ' Delete the order and then return false since the object is already deleted.
            context.DeleteObject(deletedOrder)

            Return True
        Else
            Return False
        End If
    Else
        ' Use the default behavior.
        Return False
    End If
End Function
// Method that is called when the CollectionChanged event is handled.
private bool OnCollectionChanged(
    EntityCollectionChangedParams entityCollectionChangedinfo)
{
    if (entityCollectionChangedinfo.Action ==
        NotifyCollectionChangedAction.Remove)
    {
        // Delete the related items when an order is deleted.
        if (entityCollectionChangedinfo.TargetEntity.GetType() == typeof(Order))
        {
            // Get the context and object from the supplied parameter.
            DataServiceContext context = entityCollectionChangedinfo.Context;
            Order deletedOrder = entityCollectionChangedinfo.TargetEntity as Order;

            if (deletedOrder.Order_Details.Count == 0)
            {
                // Load the related OrderDetails.
                context.LoadProperty(deletedOrder, "Order_Details");
            }

            // Delete the order and its related items;
            foreach (Order_Detail item in deletedOrder.Order_Details)
            {
                context.DeleteObject(item);
            }

            // Delete the order and then return true since the object is already deleted.
            context.DeleteObject(deletedOrder);

            return true;
        }
        else
        {
            return false;
        }
    }
    else 
    {
        // Use the default behavior.
        return false;
    }
}

Para obtener más información, vea Cómo: Personalizar comportamientos de enlace de datos (WCF Data Services).

El comportamiento predeterminado cuando un objeto se quita de una clase DataServiceCollection<T> utilizando el método Remove es que el objeto también se marca como eliminado en DataServiceContext. Para cambiar este comportamiento puede especificar un delegado para un método en el parámetro entityCollectionChanged al que se llama cuando se produce el evento CollectionChanged.

Enlazar datos con clases de datos de cliente personalizadas

Para poder cargar los objetos en la clase DataServiceCollection<T>, los objetos deben implementar la interfaz INotifyPropertyChanged. Las clases de cliente del servicio de datos que se generan al utilizar el cuadro de diálogo Agregar referencia de servicio o la herramienta DataSvcUtil.exe implementan esta interfaz. Si proporciona sus propias clases de datos de cliente, debe utilizar otro tipo de colección para el enlace de datos. Cuando los objetos cambian, debe administrar los eventos en los controles enlazados a datos para que llamen a los siguientes métodos de la clase DataServiceContext:

  • AddObject: cuando se agrega un nuevo objeto a la colección.

  • DeleteObject: cuando se elimina un objeto de la colección.

  • UpdateObject: cuando se cambia una propiedad en un objeto de la colección.

  • AddLink: cuando se agrega un objeto a una colección del objeto relacionado.

  • SetLink: cuando se agrega un objeto a una colección de objetos relacionados.

Para obtener más información, vea Actualizar el servicio de datos (WCF Data Services).

Vea también

Tasks

Cómo: Generar manualmente clases del servicio de datos del cliente (WCF Data Services)

Cómo: Agregar una referencia a un servicio de datos (WCF Data Services)