Share via


Exercise 3: Calling a WCF Service and Binding Data

In this exercise you'll create a WCF service proxy that can be used to call an existing WCF service. You'll also use a clientaccesspolicy.xml file to handle cross-domain issues and bind data to controls.

  1. Right-click on the SilverlightCustomerViewer project and select Add Service Reference from the menu.
  2. Once the Add Service Reference dialog appears click the Discover button to locate WCF services within the solution.
  3. Click on the icon to the left of CustomerService.svc to expand it. Drill-down until you can see the ICustomerService contract. Click the contract name and note that it has several service operations available.
  4. In the Namespace box supply a name of CustomerService.Proxies as shown next:

    Figure 9

    Add Services

  5. Click OK to create the WCF service proxy.
  6. Add a new Customer class into the SilverlightCustomerViewer project and change the class's namespace so that it matches with the namespace of the class generated by the WCF proxy:

    C#

    SilverlightCustomerViewer.CustomerService.Proxies

    Visual Basic

    CustomerService.Proxies
  7. Add a FullName property into the Customer class as shown next. Ensure that you mark the class with the partial keyword. This property will be displayed by the ComboBox control.

    C#

    public partial class Customer { public string FullName { get { return FirstName + " " + LastName; } } }

    Visual Basic

    Public Partial Class Customer Public ReadOnly Property FullName() As String Get Return FirstName + " " + LastName End Get End Property End Class
  8. Open the MainPage.xaml code-beside file in the editor and import the proxy namespace at the top of the code file:

    C#

    using SilverlightCustomerViewer.CustomerService.Proxies;

    Visual Basic

    Imports CustomerService.Proxies
  9. Add the following code within the constructor to hook the Loaded event to an event handler:

    C#

    Loaded += MainPage_Loaded;

    Visual Basic

    AddHandler MainPage.Loaded, MainPage_Loaded
  10. Add a MainPage_Loaded method immediately after the constructor with the following code to use the WCF service proxy created earlier and make an asynchronous data request:

    C#

    void MainPage_Loaded(object sender, RoutedEventArgs e) { var proxy = new CustomerServiceClient(); proxy.GetCustomersCompleted += proxy_GetCustomersCompleted; proxy.GetCustomersAsync(); }

    Visual Basic

    Sub MainPage_Loaded(sender as Object, e as RoutedEventArgs) Dim proxy as New CustomerServiceClient() AddHandler proxy.GetCustomersCompleted, proxy_GetCustomersCompleted proxy.GetCustomersAsync() End Sub
  11. Add the following method and associated code to handle the asynchronous callback that will be made when data from the WCF service is returned to the Silverlight application.
    Note:
    Once the WCF service proxy returns data it can be accessed through the GetCustomersCompletedEventArgs object's Result property which is typed as an ObservableCollection of Customer. The collection is assigned to the ItemsSource property of the ComboBox which is similar to the DataSource property found on data controls in ASP.NET and Windows Forms.

    C#

    void proxy_GetCustomersCompleted(object sender, GetCustomersCompletedEventArgs e) { CustomersComboBox.ItemsSource = e.Result; }

    Visual Basic

    Visual Basic Sub proxy_GetCustomersCompleted(sender as Object, _ e as GetCustomersCompletedEventArgs) CustomersComboBox.ItemsSource = e.ResultEnd Sub
  12. Back in MainPage.xaml, select the TextBlock control immediately to the right of Customer ID and select Properties from the menu.
  13. Locate the Text property and remove any text from it.
  14. Click on the Text property's black triangular icon shown next and select Apply Data Binding… from the menu:

    Figure 10

    Apply Data Binding

  15. The data binding properties window will appear and open the Source area. Click ElementName on the left and CustomersComboBox on the right to identify the ComboBox as the data binding source as shown next:

    Figure 11

    Binding to the wanted property

  16. Click on the Path area (immediately below the Source area of the data binding window) and select SelectedItem from the properties:

    Figure 12

    Binding to the wanted property

    Note:
    After removing the text from the Text property you won't see the TextBlock control on the designer surface. To get to it within the Properties window you can select the TextBlock in the XAML code or right-click on the designer and select Document Outline from the menu. You can then drill-down into the visual tree to select different controls within the designer and access their properties within the Properties window.
  17. Locate the TextBlock control modified within the previous steps in the XAML and change the Text property value to the following (notice the inclusion of the CustomerID property after SelectedItem):

    XAML

    Text="{Binding ElementName=CustomersComboBox,Path=SelectedItem.CustomerID}"
  18. Perform the previous steps to add data bindings to all of the TextBox controls in the designer. You'll need to modify the Text property of each control within the XAML as in the previous step to specify the appropriate property of the SelectedItem to bind to. The properties that each TextBox should bind to are shown next:

    TextBox

    Property to BInd

    First Name

    FirstName

    Last Name

    LastName

    Company

    CompanyName

    Email

    EmailAddress

    Phone

    Phone

  19. Note:
    Once you've defined a binding for one TextBox control's Text property using the data binding window it's often faster to copy and paste it within the XAML to the other TextBox controls and then change the property name defined in the binding.
  20. After adding the proper data bindings to the TextBox controls take a moment to look through the XAML and notice that each TextBox binding has Mode=TwoWay added to it. This allows changes to a TextBox control to be propagated back to the bound property automatically. An example of a TwoWay binding is show next:

    XAML

    Text="{Binding ElementName=CustomersComboBox,  Path=SelectedItem.FirstName,Mode=TwoWay}"
  21. Right-click the SilverlightCustomerViewer.Web project and set it as the startup project. Set the html page in the project as the startup page by right-clicking the file and selecting Set As Start Page.
  22. Press F5 to compile and run the project and notice that an error occurs once the Silverlight application loads. This is due to a cross-domain call being made from Silverlight to the WCF service. The service uses a different port then the Silverlight host Web project causing a cross-domain exception to be thrown.
  23. To fix the cross-domain issue, rename the existing clientaccesspolicy.exclude file in the CustomersService project to clientaccesspolicy.xml.
  24. Open the clientaccesspolicy.xml file in the editor and take a moment to look through the XML. Anytime Silverlight makes a call to a service in a different domain a client access policy file must be in place to successfully talk with the service. This file must be placed at the root of the service application.
  25. Run the application again and notice that data now loads in the ComboBox control. Select a customer and data should bind to the appropriate TextBlock and TextBox controls.
  26. Back in Visual Studio, double-click on both buttons in the designer to create Click event handlers.
  27. Add the following code into the Update button's click event handler to call the WCF service and pass the updated Customer object:

    C#

    var proxy = new CustomerServiceClient(); var cust = CustomersComboBox.SelectedItem as Customer; cust.ChangeTracker.State = ObjectState.Modified; proxy.SaveCustomerCompleted += (s, args) => { var opStatus = args.Result; string msg = (opStatus.Status) ? "Customer Updated!" : "Unable to update Customer: " + opStatus.Message; MessageBox.Show(msg); }; proxy.SaveCustomerAsync(cust);

    Visual Basic

    Dim proxy as New CustomerServiceClient() Dim cust = CType(CustomersComboBox.SelectedItem, Customer) cust.ChangeTracker.State = ObjectState.Modified AddHandler proxy.SaveCustomerCompleted, Sub(s, args) Dim opStatus = args.Result Dim msg As String = If(opStatus.Status, "Customer Updated!", _ "Unable to update Customer: " + opStatus.Message) MessageBox.Show(msg) End Sub proxy.SaveCustomerAsync(cust)
  28. Add the following code into the Delete button's click event handler:

    C#

    var proxy = new CustomerServiceClient(); var cust = CustomersComboBox.SelectedItem as Customer; cust.ChangeTracker.State = ObjectState.Deleted; proxy.SaveCustomerCompleted += (s, args) => { OperationStatus opStatus = args.Result; if (opStatus.Status) { ((ObservableCollection<Customer>)CustomersComboBox.ItemsSource).Remove(cust); MessageBox.Show("Customer deleted!"); } else { MessageBox.Show("Unable to delete Customer: " + opStatus.Message); } }; proxy.SaveCustomerAsync(cust);

    Visual Basic

    Dim proxy as New CustomerServiceClient() Dim cust = CType(CustomersComboBox.SelectedItem, Customer) cust.ChangeTracker.State = ObjectState.Deleted AddHandler proxy.SaveCustomerCompleted, Sub(s, args) Dim opStatus As OperationStatus = args.Result If opStatus.Status Then CType(CustomersComboBox.ItemsSource, _ ObservableCollection(Of Customer)).Remove(cust) MessageBox.Show("Customer deleted!") Else MessageBox.Show("Unable to delete Customer: " + opStatus.Message) End If End Sub proxy.SaveCustomerAsync(cust)
  29. Run the application and test the update and delete functionality.