How to: Create an Asynchronous Windows Presentation Framework Application (WCF Data Services)

With WCF Data Services, you can bind data obtained from a data service to UI element of a Windows Presentation Framework (WPF) application. For more information, see Binding Data to Controls (WCF Data Services).You can also execute operations against the data service in an asynchronous manner, which enables the application to continue to respond while waiting for a response to a data service request. Applications for Silverlight are required to access the data service asynchronously. For more information, see Asynchronous Operations (WCF Data Services).

This topic shows how to access a data service asynchronously and bind the results to elements of a WPF application. The examples in this topic use the Northwind sample data service and autogenerated client data service classes. This service and the client data classes are created when you complete the WCF Data Services quickstart.

Example

The following XAML defines the window of the WPF application.

    <Window x:Class="CustomerOrdersAsync"
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            Height="423" Width="679" Loaded="Window_Loaded" >
    <Grid Name="LayoutRoot">
        <StackPanel Orientation="Vertical" Height="Auto" 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>
    </Grid>
</Window>

The following code-behind page for the XAML file executes an asynchronous query by using the data service and binds the results to elements in the WPF window.

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
Imports System.Windows.Navigation
Imports System.Windows.Shapes
Imports NorthwindClient.Northwind
Imports System.Data.Services.Client
Imports System.Windows.Threading

'/ <summary>
'/ Interaction logic for OrderItems.xaml
'/ </summary>
Partial Public Class CustomerOrdersAsync
    Inherits Window

    Dim context As NorthwindEntities
    Private Shared customerBinding As DataServiceCollection(Of Customer)
    Private Const customerCountry As String = "Germany"

    ' Change this URI to the service URI for your implementation.
    Private Const svcUri As String = "https://localhost:12345/Northwind.svc/"

    ' Define a persisted result.
    Private Shared currentResult As IAsyncResult

    Delegate Sub DispatcherDelegate()

    Private Sub Window_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' Initialize the context.
        context = New NorthwindEntities(New Uri(svcUri))

        ' Define the delegate to callback into the process
        Dim callback As AsyncCallback = AddressOf OnQueryCompleted

        ' Define a query that returns customers and orders for a specific country.
        Dim query As DataServiceQuery(Of Customer) = _
        context.Customers.Expand("Orders") _
        .AddQueryOption("filter", "Country eq '" + customerCountry + "'")

        Try
            ' Begin asynchronously saving changes Imports the 
            ' specified handler and query object state.
            query.BeginExecute(callback, query)

        Catch ex As DataServiceClientException
            MessageBox.Show(ex.ToString())
        End Try
    End Sub
    Private Sub OnQueryCompleted(ByVal result As IAsyncResult)
        ' Persist the query result for the delegate.
        currentResult = result

        ' Use the Dispatcher to ensure that the 
        ' asynchronous call returns in the correct thread.
        Dispatcher.BeginInvoke(New DispatcherDelegate(AddressOf QueryCompletedByDispatcher))
    End Sub
    ' Handle the query callback.        
    Private Sub QueryCompletedByDispatcher()
        Try
            ' Get the original query back from the result.
            Dim query = CType(currentResult.AsyncState, DataServiceQuery(Of Customer))

            ' Instantiate the binding collection imports the 
            ' results of the query execution.
            customerBinding = New DataServiceCollection(Of Customer)( _
                        query.EndExecute(currentResult))

            ' Bind the collection to the root element of the UI.
            Me.LayoutRoot.DataContext = customerBinding
        Catch ex As DataServiceRequestException
            MessageBox.Show(ex.ToString())
        End Try
    End Sub
    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 OnSaveChangesCompleted

        Try
            ' Start the asynchronous call to save changes.
            context.BeginSaveChanges(callback, Nothing)
        Catch ex As DataServiceClientException
            MessageBox.Show(ex.ToString())
        End Try
    End Sub
    Private Sub OnSaveChangesCompleted(ByVal result As IAsyncResult)
        ' Persist the query result for the delegate.
        currentResult = result

        ' Use the Dispatcher to ensure that the operation returns in the UI thread.
        Me.Dispatcher.BeginInvoke(New DispatcherDelegate(AddressOf SaveChangesCompletedByDispatcher))
        ' Handle the query callback.
    End Sub
    Private Sub SaveChangesCompletedByDispatcher()
        Try
            ' Complete the save changes operation.
            context.EndSaveChanges(currentResult)
        Catch ex As DataServiceRequestException
            MessageBox.Show(ex.ToString())
        End Try
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using NorthwindClient.Northwind;
using System.Data.Services.Client;
using System.Windows.Threading;

namespace NorthwindClient
{
    /// <summary>
    /// Interaction logic for OrderItems.xaml
    /// </summary>
    public partial class CustomerOrdersAsync : Window
    {
        private NorthwindEntities context;
        private DataServiceCollection<Customer> customerBinding;
        private const string customerCountry = "Germany";

        // Change this URI to the service URI for your implementation.
        private const string svcUri = "https://localhost:12345/Northwind.svc/";

        // Delegate that returns void for the query result callback.
        private delegate void OperationResultCallback();

        public CustomerOrdersAsync()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // Initialize the context.
            context = new NorthwindEntities(new Uri(svcUri));

            // Define a query that returns customers and orders for a specific country.
            DataServiceQuery<Customer> query = context.Customers.Expand("Orders")
                .AddQueryOption("filter", "Country eq '" + customerCountry + "'");

            try
            {
                // Begin asynchronously saving changes using the 
                // specified handler and query object state.
                query.BeginExecute(OnQueryCompleted, query);
            }
            catch (DataServiceClientException ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void OnQueryCompleted(IAsyncResult result)
        {
            // Get the original query object from the state cache.
            DataServiceQuery<Customer> query =
                   (DataServiceQuery<Customer>)result.AsyncState;


            // Use the Dispatcher to ensure that the query returns in the UI thread.
            this.Dispatcher.BeginInvoke(new OperationResultCallback(delegate
            {
                try
                {
                    // Instantiate the binding collection using the 
                    // results of the query execution.
                    customerBinding = new DataServiceCollection<Customer>(
                        query.EndExecute(result));

                    // Bind the collection to the root element of the UI.
                    this.LayoutRoot.DataContext = customerBinding;
                }
                catch (DataServiceRequestException ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }),null);
        }
        private void saveChangesButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Start the asynchronous call to save changes.
                context.BeginSaveChanges(OnSaveChangesCompleted, null);
            }
            catch (DataServiceClientException ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
        private void OnSaveChangesCompleted(IAsyncResult result)
        {
            // Use the Dispatcher to ensure that the operation returns in the UI thread.
            this.Dispatcher.BeginInvoke(new OperationResultCallback(delegate
            {
                try
                {
                    // Complete the save changes operation.
                    context.EndSaveChanges(result);
                }
                catch (DataServiceRequestException ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }), null);
        }
    }
}

See Also

Other Resources

Data Client (WCF Data Services)