Procédure : lier des données de service de données aux contrôles (client Silverlight)
Avec Services de données WCF, vous pouvez lier des contrôles Silverlight tels que les contrôles ListBox ou ComboBox à une instance de DataServiceCollection<T>. Cette classe gère les événements déclenchés par les contrôles pour garder le DataServiceContext synchronisé avec les modifications apportées aux données dans ces contrôles. Une DataServiceCollection<T> est définie en fonction d'une DataServiceQuery<TElement>. Lorsqu'elle est exécutée, cette requête retourne un flux Protocole OData (Open Data) qui fournit les objets pour la collection.
Les procédures de cette rubrique indiquent comment exécuter les tâches suivantes :
(Facultatif) Activer la fonctionnalité de pagination dans le service de données Northwind.
Créer une application Silverlight.
Générer des classes de service de données client qui prennent en charge la liaison automatique de données.
Interroger le service de données.
Lier les résultats aux contrôles dans l'application.
Utiliser une instance CollectionViewSource pour simplifier la liaison des objets Order et Order_Detail maître/détail. Pour cela, définissez la propriété Source de la CollectionViewSource sur la DataServiceCollection<T> maître. La liaison de données des contrôles est définie dans le XAML de telle sorte que toute modification apportée à la Order sélectionnée entraîne la modification des Order_Details affichés lors du chargement de la collection. Pour plus d'informations, consultez How to: Bind to Hierarchical Data and Create a Master/Details View.
Notes
La classe CollectionViewSource n'est pas prise en charge dans Silverlight 3.
Cet exemple indique comment lier un flux OData lorsque la pagination est activée dans le service de données. La pagination d'un flux de données est prise en charge par les versions 2.0 et ultérieures du protocole OData.
L'exemple du service de données Northwind auquel l'application accède est créé lorsque vous effectuez le démarrage rapide Services de données WCF. Vous pouvez également utiliser l'exemple de service de données Northwind public publié sur le site Web OData ; cet exemple de service de données est en lecture seule et retourne une erreur si vous tentez d'enregistrer les modifications apportées.
Pou activer la pagination dans l'exemple du service de données Northwind
Dans l'Explorateur de solutions, sous votre projet ASP.NET, double-cliquez sur Northwind.svc.
La page de code de l'exemple du service de données Northwind s'ouvre.
Dans le code du service de données, ajoutez le code suivant à la méthode InitializeService :
' Set the data service version to V2 to support paging. config.DataServiceBehavior.MaxProtocolVersion = _ System.Data.Services.Common.DataServiceProtocolVersion.V2 ' Set paging limits for the Customers and Orders entity sets. ' These limits are set very low to demonstrate paging with the ' Northwind database. Paging should be configured to optimize ' data service performance. config.SetEntitySetPageSize("Orders", 2) config.SetEntitySetPageSize("Order_Details", 2)
// Set the data service version to V2 to support paging. config.DataServiceBehavior.MaxProtocolVersion = System.Data.Services.Common.DataServiceProtocolVersion.V2; // Set paging limits for the Customers and Orders entity sets. // These limits are set very low to demonstrate paging with the // Northwind database. Paging should be configured to optimize // data service performance. config.SetEntitySetPageSize("Orders", 2); config.SetEntitySetPageSize("Order_Details", 2);
Cela permet d'activer la pagination des jeux d'entités Orders et Order_Details.
Pour créer l'application du projet Silverlight
Dans l'Explorateur de solutions, cliquez avec le bouton droit sur Solution, pointez sur Ajouter, puis sélectionnez Nouveau projet.
Dans la boîte de dialogue Ajouter un nouveau projet, sélectionnez Silverlight dans le volet Catégories, puis sélectionnez le modèle Application Silverlight. Attribuez le nom DataBindingSample au projet.
Dans la boîte de dialogue Ajouter une application Silverlight, sélectionnez Héberger l'application Silverlight sur un site Web nouveau ou existant dans la solution. Sélectionnez Ajouter une page de test qui référence l'application et Définir comme page de démarrage.
Cliquez sur OK.
Cette procédure crée l'application pour Silverlight.
Pour ajouter une référence de service de données au projet
Cliquez avec le bouton droit sur le projet DataBindingSample, puis cliquez sur Ajouter une référence de service, puis sur Découvrir.
Cette opération affiche le service de données Northwind que vous avez créé dans la première tâche.
Dans la zone de texte Espace de noms, tapez Northwind, puis cliquez sur OK.
Cette opération ajoute un nouveau fichier de code au projet qui contient les classes de données utilisées pour accéder et interagir avec les ressources du service de données sous la forme d'objets. Les classes de données sont créées dans l'espace de noms DataBindingSample.Northwind.
Pour définir l'interface utilisateur de l'application cliente
Dans l'Explorateur de solutions sous DataBindingSample, cliquez avec le bouton droit sur Références, puis cliquez sur Ajouter une référence.
La boîte de dialogue Ajouter une référence s'affiche.
Sélectionnez System.Windows.Controls.Data, puis cliquez sur OK.
Dans l'Explorateur de solutions, double-cliquez sur MainPage.xaml. La balisage XAML s'ouvre pour la classe Page représentant l'interface utilisateur de l'application Silverlight.
Remplacez le balisage XAML existant par le balisage suivant, qui définit l'interface utilisateur de l'application :
<!-- NOTE: By convention, the sdk prefix indicates a URI-based XAML namespace declaration for Silverlight SDK client libraries. This namespace declaration is valid for Silverlight 4 only. In Silverlight 3, you must use individual XAML namespace declarations for each CLR assembly and namespace combination outside the scope of the default Silverlight XAML namespace. For more information, see the help topic "Prefixes and Mappings for Silverlight Libraries". --> <UserControl x:Class="MainPage" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sdk="https://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Loaded="MainPage_Loaded" mc:Ignorable="d" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:my="clr-namespace:DataBindingSample.Northwind" d:DesignHeight="371" d:DesignWidth="0"> <UserControl.Resources> <CollectionViewSource x:Key="OrdersViewSource" d:DesignSource="{d:DesignInstance my:Order, CreateList=True}" /> <CollectionViewSource x:Key="OrdersOrder_DetailsViewSource" Source="{Binding Path=Order_Details, Source={StaticResource OrdersViewSource}}" /> </UserControl.Resources> <StackPanel Orientation="Vertical" Margin="10" Height="Auto" Name="LayoutRoot" Width="450"> <StackPanel Orientation="Horizontal"> <sdk:Label Content="Customer ID:"/> <TextBox Name="customerId" Text="ALFKI" Margin="10" Width="100"/> <Button Name="getCustomerOrders" Content="Get Orders" Height="25" Width="80" Click="getCustomerOrders_Click" /> </StackPanel> <StackPanel Name="ordersStackPanel" VerticalAlignment="Top" Orientation="Vertical" DataContext="{StaticResource OrdersViewSource}"> <Grid HorizontalAlignment="Left" Name="ordersGrid" VerticalAlignment="Top"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <sdk:Label Content="Order:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" /> <ComboBox DisplayMemberPath="OrderID" Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" ItemsSource="{Binding}" Margin="3" Name="OrderIDComboBox" VerticalAlignment="Center" Width="120" SelectionChanged="ordersList_SelectionChanged"> <ComboBox.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel /> </ItemsPanelTemplate> </ComboBox.ItemsPanel> </ComboBox> <sdk:Label Content="Freight:" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" /> <TextBox Grid.Column="3" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="FreightTextBox" Text="{Binding Path=Freight, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" /> <sdk:Label Content="Required Date:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" /> <sdk:DatePicker Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="RequiredDateDatePicker" SelectedDate="{Binding Path=RequiredDate, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" /> <sdk:Label Content="Order Date:" Grid.Column="2" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" /> <TextBox Grid.Column="3" Grid.Row="1" Height="23" HorizontalAlignment="Left" Width="120" Margin="3" Name="OrderDateTextBlock" Text="{Binding Path=OrderDate}" VerticalAlignment="Center" /> </Grid> </StackPanel> <StackPanel DataContext="{StaticResource OrdersOrder_DetailsViewSource}" Orientation="Vertical"> <sdk:Label Content="Order items:" Margin="10"/> <sdk:DataGrid AutoGenerateColumns="False" Height="170" ItemsSource="{Binding}" Name="Order_DetailsDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" Width="400"> <sdk:DataGrid.Columns> <sdk:DataGridTextColumn x:Name="ProductIDColumn" Binding="{Binding Path=ProductID}" Header="Product" Width="SizeToHeader" /> <sdk:DataGridTextColumn x:Name="QuantityColumn" Binding="{Binding Path=Quantity}" Header="Quantity" Width="SizeToHeader" /> <sdk:DataGridTextColumn x:Name="DiscountColumn" Binding="{Binding Path=Discount}" Header="Discount" Width="SizeToHeader" /> <sdk:DataGridTextColumn x:Name="UnitPriceColumn" Binding="{Binding Path=UnitPrice}" Header="Unit Price" Width="SizeToHeader" /> </sdk:DataGrid.Columns> </sdk:DataGrid> </StackPanel> <Button Name="saveChangesButton" Content="Save Changes" HorizontalAlignment="Right" Click="saveChangesButton_Click" Width="100" Height="25" Margin="10"/> </StackPanel> </UserControl>
Notes
Pour une application C#, vous devez inclure l'espace de noms dans l'attribut Class du UserControl.L'espace de noms par défaut n'est pas requis pour une application Visual Basic.
Pour ajouter le code liant les données du service de données aux contrôles de l'application Silverlight
Dans l'Explorateur de solutions sous DataBindingSample, ouvrez la page de code pour le fichier MainPage.xaml et ajoutez l'instruction using suivante (Imports en Visual Basic).
using System.Windows.Data; using System.Data.Services.Client; using DataBindingSample.Northwind;
Ajoutez les déclarations suivantes à la classe MainPage :
Dim context As NorthwindEntities Dim trackedOrders As DataServiceCollection(Of Order) Dim selectedOrder As Order Dim ordersViewSource As CollectionViewSource
NorthwindEntities context; DataServiceCollection<Order> trackedOrders; Order selectedOrder; CollectionViewSource ordersViewSource;
Ajoutez la méthode MainPage_Loaded suivante à la classe MainPage :
Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Initialize the data service context. context = _ New NorthwindEntities(New Uri("https://localhost:54321/Northwind.svc")) ' Initialize the binding and view source collections. trackedOrders = New DataServiceCollection(Of Order)() ordersViewSource = CType(Me.Resources("OrdersViewSource"), CollectionViewSource) ' Define a handler for the LoadCompleted event of the collection. AddHandler trackedOrders.LoadCompleted, _ AddressOf trackedOrders_LoadCompleted End Sub
private void MainPage_Loaded(object sender, RoutedEventArgs e) { // Initialize the data service context. context = new NorthwindEntities(new Uri("Northwind.svc", UriKind.Relative)); // Initialize the binding and view source collections. trackedOrders = new DataServiceCollection<Order>(); ordersViewSource = (CollectionViewSource)this.Resources["OrdersViewSource"]; // Define a handler for the LoadCompleted event of the binding collection. trackedOrders.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(trackedOrders_LoadCompleted); }
Lorsque la page est chargée, ce code initialise le contenu et les collections de liaisons et enregistre la méthode pour gérer l'événement LoadCompleted déclenché par la collection de liaisons.
Insérez le code suivant dans la classe MainPage :
Private Sub getCustomerOrders_Click(ByVal sender As Object, _ ByVal e As RoutedEventArgs) ' Define a query that returns orders for a give customer. Dim query = From orderByCustomer In context.Orders _ Where orderByCustomer.Customer.CustomerID = _ Me.customerId.Text _ Select orderByCustomer ' Asynchronously load the result of the query. trackedOrders.LoadAsync(query) ' Disable the button until the loading is complete. getCustomerOrders.IsEnabled = False End Sub Private Sub trackedOrders_LoadCompleted(ByVal sender As Object, _ ByVal e As LoadCompletedEventArgs) If e.Error Is Nothing Then ' Load all pages of Orders before binding. If trackedOrders.Continuation IsNot Nothing Then trackedOrders.LoadNextPartialSetAsync() Else ' Bind the root StackPanel element to the collection ' related object binding paths are defined in the XAML. ordersViewSource.Source = trackedOrders ' Re-enable the button since the loading is complete. getCustomerOrders.IsEnabled = True End If Else MessageBox.Show(String.Format("An error has occured: {0}", e.Error.Message)) getCustomerOrders.IsEnabled = True End If End Sub
private void getCustomerOrders_Click(object sender, RoutedEventArgs e) { // Reset the grids. ordersViewSource.Source = null; // Define a query that returns orders for a give customer. var query = from orderByCustomer in context.Orders where orderByCustomer.Customer.CustomerID == this.customerId.Text select orderByCustomer; // Asynchronously load the result of the query. trackedOrders.LoadAsync(query); // Disable the button until the loading is complete. getCustomerOrders.IsEnabled = false; } private void trackedOrders_LoadCompleted(object sender, LoadCompletedEventArgs e) { if (e.Error == null) { // Load all pages of Orders before binding. if (trackedOrders.Continuation != null) { trackedOrders.LoadNextPartialSetAsync(); } else { // Bind the root StackPanel element to the collection; // related object binding paths are defined in the XAML. ordersViewSource.Source = trackedOrders; // Re-enable the button since the loading is complete. getCustomerOrders.IsEnabled = true; } } else { MessageBox.Show(string.Format("An error has occured: {0}",e.Error.Message)); getCustomerOrders.IsEnabled = true; } }
Cliquez sur le bouton getCustomerOrders pour exécuter les opérations suivantes :
La méthode LoadAsync est appelée dans la collection de liaisons afin d'exécuter la requête fournie qui retourne les commandes filtrées par l'ID client fourni.
La méthode LoadNextPartialSetAsync est appelée afin de charger les pages de résultats suivantes dès lors que la propriété Continuation retourne une valeur.
La collection d'objets Order chargés est liée à la propriété Source de la CollectionViewSource, qui constitue l'objet de liaison maître pour tous les contrôles de la page.
Insérez le code suivant dans la classe MainPage :
Private Sub ordersList_SelectionChanged(ByVal sender As Object, _ ByVal e As SelectionChangedEventArgs) ' Get the selected Order in the DataGrid. Dim ordersList As ComboBox = CType(sender, ComboBox) selectedOrder = CType(ordersList.SelectedItem, Order) If Not selectedOrder Is Nothing Then ' Asynchronously load related items, if they are not already loaded. If selectedOrder.Order_Details.Count = 0 Then ' Register the method to handle the LoadCompleted event. AddHandler selectedOrder.Order_Details.LoadCompleted, _ AddressOf Order_Details_LoadCompleted Try ' Load the related items. selectedOrder.Order_Details.LoadAsync() Catch ex As InvalidOperationException MessageBox.Show(String.Format("An error has occured: {0}", _ ex.Message)) End Try End If End If End Sub Private Sub Order_Details_LoadCompleted(ByVal sender As Object, _ ByVal e As LoadCompletedEventArgs) Dim trackedItems As DataServiceCollection(Of Order_Detail) = _ CType(sender, DataServiceCollection(Of Order_Detail)) ' Load any remaining pages of Order_Details. If Not trackedItems.Continuation Is Nothing Then Try trackedItems.LoadNextPartialSetAsync() Catch ex As InvalidOperationException MessageBox.Show(String.Format("An error has occured: {0}", _ ex.Message)) End Try End If End Sub
private void ordersList_SelectionChanged(object sender, SelectionChangedEventArgs e) { // Get the selected Order in the DataGrid. ComboBox ordersList = sender as ComboBox; selectedOrder = ((Order)(ordersList.SelectedItem)); if (selectedOrder != null) { // Asynchronously load related items, if they are not already loaded. if (selectedOrder.Order_Details.Count == 0) { // Register the method to handle the LoadCompleted event. selectedOrder.Order_Details.LoadCompleted += new EventHandler<LoadCompletedEventArgs>( Order_Details_LoadCompleted); try { // Load the related items. selectedOrder.Order_Details.LoadAsync(); } catch (InvalidOperationException ex) { MessageBox.Show(string.Format("An error has occured: {0}", ex.Message)); } } } } void Order_Details_LoadCompleted(object sender, LoadCompletedEventArgs e) { DataServiceCollection<Order_Detail> trackedItems = sender as DataServiceCollection<Order_Detail>; // Load any remaining pages of Order_Details. if (trackedItems.Continuation != null) { try { trackedItems.LoadNextPartialSetAsync(); } catch (InvalidOperationException ex) { MessageBox.Show(string.Format("An error has occured: {0}", ex.Message)); } } }
La méthode ordersList_SelectionChanged gère l'événement SelectionChanged. Lorsque l'utilisateur sélectionne une commande dans la ComboBox, les opérations suivantes sont exécutées :
La méthode Order_Details_LoadCompleted est enregistrée pour gérer l'événement LoadCompleted déclenché par la DataServiceCollection<T> qui représente les éléments associés à la commande sélectionnée.
La méthode LoadAsync est appelée afin de charger de manière asynchrone les objets Order_Details associés à la Order sélectionnée dans la ComboBox.
La méthode LoadNextPartialSetAsync est appelée afin de charger les pages de résultats suivantes dès lors que la propriété Continuation retourne une valeur.
Les éléments chargés sont propagés dans la DataGrid par la CollectionViewSource enfant.
Insérez le code suivant qui enregistre les modifications dans la classe MainPage :
' We need to persist the result of an operation ' to be able to invoke the dispatcher. Private currentResult As IAsyncResult Private Sub saveChangesButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Define the delegate to callback into the process Dim callback As AsyncCallback = AddressOf OnChangesSaved Try ' Start the saving changes operation. This needs to be a ' batch operation in case we are added a new object with ' a new relationship. context.BeginSaveChanges(SaveChangesOptions.Batch, _ callback, context) Catch ex As Exception MessageBox.Show(String.Format( _ "The changes could not be saved to the data service.\n" _ & "The following error occurred: {0}", ex.Message)) End Try End Sub Private Sub OnChangesSaved(ByVal result As IAsyncResult) ' Persist the result for the delegate. currentResult = result ' Use the Dispatcher to ensure that the ' asynchronous call returns in the correct thread. Dispatcher.BeginInvoke(AddressOf ChangesSavedByDispatcher) End Sub Private Sub ChangesSavedByDispatcher() Dim errorOccured As Boolean = False context = CType(currentResult.AsyncState, NorthwindEntities) Try ' Complete the save changes operation and display the response. Dim response As DataServiceResponse = _ context.EndSaveChanges(currentResult) For Each changeResponse As ChangeOperationResponse In response If changeResponse.Error IsNot Nothing Then errorOccured = True Next If Not errorOccured Then MessageBox.Show("The changes have been saved to the data service.") Else MessageBox.Show("An error occured. One or more changes could not be saved.") End If Catch ex As Exception ' Display the error from the response. MessageBox.Show(String.Format("The following error occured: {0}", ex.Message)) End Try End Sub
private void saveChangesButton_Click(object sender, RoutedEventArgs e) { try { // Start the saving changes operation. This needs to be a // batch operation in case we are added a new object with // a new relationship. context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context); } catch (Exception ex) { MessageBox.Show(string.Format("The changes could not be saved to the data service.\n" + "The following error occurred: {0}", ex.Message)); } } private void OnChangesSaved(IAsyncResult result) { bool errorOccured = false; // Use the Dispatcher to ensure that the // asynchronous call returns in the correct thread. Dispatcher.BeginInvoke(() => { context = result.AsyncState as NorthwindEntities; try { // Complete the save changes operation and display the response. DataServiceResponse response = context.EndSaveChanges(result); foreach (ChangeOperationResponse changeResponse in response) { if (changeResponse.Error != null) errorOccured = true; } if (!errorOccured) { MessageBox.Show("The changes have been saved to the data service."); } else { MessageBox.Show("An error occured. One or more changes could not be saved."); } } catch (Exception ex) { // Display the error from the response. MessageBox.Show(string.Format("The following error occured: {0}", ex.Message)); } } ); }
Ce code renvoie de façon asynchrone les modifications apportées aux contrôles liés aux données au service de données.
Voir aussi
Autres ressources
Démarrage rapide WCF Data Services pour Silverlight
WCF Data Services (Silverlight)
WCF Data Services Tasks for Silverlight