Querying the Data Service (WCF Data Services/Silverlight)
Microsoft Silverlight will reach end of support after October 2021. Learn more.
In this task, you will query the data service and bind the returned entity data to controls in the application, which you defined in the previous task. You create and execute the query asynchronously by using the NorthwindEntities class, which derives from the DataServiceContext class. You generated this context class from the data service metadata by using the add service reference tool in the previous task. For more information, see Working with .NET Framework Client Libraries (WCF Data Services).
Note: |
---|
Because you asynchronously access the data service by using network protocols, you must use the BeginInvoke method of the Dispatcher class to correctly marshal the response operation back to the main application thread (the UI thread) of your Silverlight-based application. For more information, see Synchronizing Data for Multithreading. |
To query for orders that belong to a specified customer
Open the MainPage.xaml.cs source code file of the Silverlight project.
Add the following using directives (Imports in Visual Basic):
Imports System.Windows Imports System.Data.Services.Client Imports System.Collections.ObjectModel Imports System.Collections.Specialized Imports SilverlightClient.Northwind
using System.Data.Services.Client; using System.Collections.ObjectModel; using System.Collections.Specialized; using SilverlightClient.Northwind;
Add the following type definitions to the MainPage class:
Dim svcContext As NorthwindEntities Dim ordersBindingCollection As ObservableCollection(Of Order) Dim detailsBindingCollection As ObservableCollection(Of Order_Detail) Dim orderToken As DataServiceQueryContinuation(Of Order) Dim itemToken As DataServiceQueryContinuation(Of Order_Detail) Dim currentOrder As Order
NorthwindEntities svcContext; ObservableCollection<Order> ordersBindingCollection; ObservableCollection<Order_Detail> detailsBindingCollection; DataServiceQueryContinuation<Order> orderToken; DataServiceQueryContinuation<Order_Detail> itemToken; Order currentOrder;
In the public constructor method for the MainPage class, insert the following code that initializes the data binding collections.
' Create the binding collections. ordersBindingCollection = New ObservableCollection(Of Order)() detailsBindingCollection = New ObservableCollection(Of Order_Detail)() ' Initialize the tokens used to track paged responses. orderToken = Nothing itemToken = Nothing
// Create the binding collections. ordersBindingCollection = new ObservableCollection<Order>(); detailsBindingCollection = new ObservableCollection<Order_Detail>(); // Initialize the tokens used to track paged responses. orderToken = null; itemToken = null;
Add the following methods to the MainPage class. These methods are called when the getCustomerOrders button is clicked. The first method reinitializes the DataServiceContext and clears the binding collections. The second method obtains an instance of DataServiceQuery<TElement> of the Customers type from the context. The AddQueryOption method is called two times on this query; one time to add a $filter query option to return only a specific customer and again to add an $expand query option to return orders related to the returned customer. The returned Orders objects are loaded into an ObservableCollection<T> that is bound to the DataGrid.
Private Sub ResetBindingData() ' Create a new data service context. svcContext = _ New NorthwindEntities(New Uri("https://localhost:54321/Northwind.svc")) ordersBindingCollection.Clear() detailsBindingCollection.Clear() End Sub ' We need to persist the result of an operation ' to be able to invoke the dispatcher. Private currentResult As IAsyncResult Private Sub getCustomerOrders_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Instantiate the data service context and clear any existing bindings. ResetBindingData() ' Define the delegate to callback into the process Dim callback As AsyncCallback = AddressOf OnCustomerOrdersQueryComplete ' Define a LINQ query to return the specifed customer and related orders. Dim query = From o In svcContext.Orders Where o.CustomerID = Me.customerId.Text Select o Try ' Begin execution of the query as a DataServiceQuery. CType(query, DataServiceQuery(Of Order)).BeginExecute(callback, query) Catch ex As Exception messageTextBlock.Text = ex.Message End Try End Sub Private Sub OnCustomerOrdersQueryComplete(ByVal result As IAsyncResult) ' Cache the query result for the delegate. currentResult = result ' Use the Dispatcher to ensure that the ' asynchronous call returns in the correct thread. Dispatcher.BeginInvoke(AddressOf QueryCompletedByDispatcher) End Sub Private Sub QueryCompletedByDispatcher() Dim response As IEnumerable(Of Order) = Nothing ' Define the delegate to callback into the process Dim callback As AsyncCallback = AddressOf OnCustomerOrdersQueryComplete Try If Not orderToken Is Nothing Then ' This is not the first page, so we get back the context. svcContext = CType(currentResult.AsyncState, NorthwindEntities) response = svcContext.EndExecute(Of Order)(currentResult) Else ' Since this is the first page, we get back the query. Dim query = CType(currentResult.AsyncState, DataServiceQuery(Of Order)) ' Get the response of the query. response = query.EndExecute(currentResult) End If ' Enumeration executes the query. For Each o As Order In response ' Add the order to the binding collection. ordersBindingCollection.Add(o) Next ' Get the continuation token from the response. orderToken = CType(response, QueryOperationResponse(Of Order)).GetContinuation() If Not orderToken Is Nothing Then ' Get the next page if a continuation token was returned. svcContext.BeginExecute(Of Order)(orderToken, _ callback, svcContext) Else ' There are no more response pages, so bind the grid control ' to the collection and update the layout. Me.ordersGrid.DataContext = ordersBindingCollection Me.ordersGrid.UpdateLayout() ' Hide the relationship property columns. Me.ordersGrid.Columns(0).Visibility = Visibility.Collapsed Me.ordersGrid.Columns(1).Visibility = Visibility.Collapsed Me.ordersGrid.Columns(2).Visibility = Visibility.Collapsed Me.ordersGrid.Columns(11).Visibility = Visibility.Collapsed Me.ordersGrid.Columns(14).Visibility = Visibility.Collapsed Me.ordersGrid.Columns(15).Visibility = Visibility.Collapsed ' Select the first order, if any orders exist. If ordersBindingCollection.Count > 0 Then Me.ordersGrid.SelectedIndex = 0 End If End If Catch ex As DataServiceQueryException Me.messageTextBlock.Text = String.Format("Error: {0} - {1}", _ ex.Response.StatusCode.ToString(), ex.Response.Error.Message) End Try End Sub
private void ResetBindingData() { // Create a new data service context. svcContext = new NorthwindEntities(new Uri("https://localhost:12345/Northwind.svc")); ordersBindingCollection.Clear(); detailsBindingCollection.Clear(); } private void getCustomerOrders_Click(object sender, RoutedEventArgs e) { // Instantiate the data service context and clear any existing bindings. ResetBindingData(); // Define a LINQ query to return the specifed customer and related orders. var query = from o in svcContext.Orders where o.CustomerID == this.customerId.Text select o; try { // Begin execution of the query as a DataServiceQuery. ((DataServiceQuery<Order>)query).BeginExecute(OnCustomerOrdersQueryComplete, query); } catch (Exception ex) { messageTextBlock.Text = ex.Message; } } private void OnCustomerOrdersQueryComplete(IAsyncResult result) { // Use the Dispatcher to ensure that the // asynchronous call returns in the correct thread. Dispatcher.BeginInvoke(() => { IEnumerable<Order> response = null; try { if (orderToken != null) { // This is not the first page, so we get back the context. svcContext = result.AsyncState as NorthwindEntities; response = svcContext.EndExecute<Order>(result); } else { // Since this is the first page, we get back the query. var query = result.AsyncState as DataServiceQuery<Order>; // Get the response of the query. response = query.EndExecute(result); } // Enumeration executes the query. foreach (Order o in response) { // Add the order to the binding collection. ordersBindingCollection.Add(o); } // Get the continuation token from the response. orderToken = ((QueryOperationResponse<Order>)response).GetContinuation(); if (orderToken != null) { // Get the next page if a continuation token was returned. svcContext.BeginExecute<Order>(orderToken, OnCustomerOrdersQueryComplete, svcContext); } else { // There are no more response pages, so bind the grid control // to the collection and update the layout. this.ordersGrid.DataContext = ordersBindingCollection; this.ordersGrid.UpdateLayout(); // Hide the relationship property columns. this.ordersGrid.Columns[0].Visibility = Visibility.Collapsed; this.ordersGrid.Columns[1].Visibility = Visibility.Collapsed; this.ordersGrid.Columns[2].Visibility = Visibility.Collapsed; this.ordersGrid.Columns[11].Visibility = Visibility.Collapsed; this.ordersGrid.Columns[14].Visibility = Visibility.Collapsed; this.ordersGrid.Columns[15].Visibility = Visibility.Collapsed; // Select the first order, if any orders exist. if (ordersBindingCollection.Count > 0) { this.ordersGrid.SelectedIndex = 0; } } } catch (DataServiceQueryException ex) { this.messageTextBlock.Text = string.Format("Error: {0} - {1}", ex.Response.StatusCode.ToString(), ex.Response.Error.Message); } } ); }
To build and run the application
From the Debug menu, select Start Debugging or Start Without Debugging.
This builds and starts the application.
When the page loads, enter a value in the Customer ID text box (a valid value of ALFKI is provided), and then click Get Orders.
This displays the orders that belong to that customer.
Next Steps
You have successfully created a query that returns a specific Customers object and related Orders objects from the Northwind data service, and you have bound those Orders objects to a grid control. Next, you will load specific Order_Details objects from the data service and bind them to a second data grid: