Connecting to the Service
The code that you have to write to interact with the OData service is the same as in Part 3, when talking about Windows Phone 7.5. This is because the OData client library offers the same implementation and can be used the same way for both versions. There are basically two differences: 1) as I said previously, the Windows Phone 8 emulator cannot access local resources directly, so you have to specify the IP address for the server rather than the service name; and 2) the code that creates an instance of the proxy class for the service is placed inside the OnNavigatedTo event handler. Otherwise, the code is the same as that used for Windows Phone 7.5 and for Windows 8 Store Apps in Part 4.
Listing 3 shows the code that's responsible for establishing a connection to the service-passing credentials, as well as for keeping in memory the information retrieved from the service.
Listing 3Connecting to the OData service and declaring class-level variables.
'The following directives are required 'Imports System.Data.Services.Client 'Imports MobileOrdersClient.OrdersServiceReference 'Store the service URL. Replace localhost with your server's name Private Shared ReadOnly ServiceUri As New _ Uri("http://192.168.1.3/ExposingOData/ApplicationData.svc") 'Two collections for storing the list of entities exposed by the service Private Property orders As DataServiceCollection(Of Order) Private customers As DataServiceCollection(Of Customer) 'Represent the LightSwitch's intrinsic data Private applicationData As OrdersServiceReference.ApplicationData 'Constructor Public Sub New() InitializeComponent() SupportedOrientations = SupportedPageOrientation.Portrait Or SupportedPageOrientation.Landscape End Sub Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs) 'Start an instance of the WCF service If Me.applicationData Is Nothing Then Me.applicationData = New OrdersServiceReference.ApplicationData(ServiceUri) End If 'Pass credentials of a LightSwitch user Me.applicationData.Credentials = New NetworkCredential("TestUser", "TestUser$") 'Create instances of collections to store data Me.orders = New DataServiceCollection(Of Order)(applicationData) Me.customers = New DataServiceCollection(Of Customer)(applicationData) 'Declare event handlers for handling loaded data AddHandler Me.orders.LoadCompleted, AddressOf orders_LoadCompleted AddHandler Me.customers.LoadCompleted, AddressOf customers_LoadCompleted 'Load customers and orders loadCustomers() loadOrders() End Sub
As a reminder, the DataServiceCollection(Of T) class allows for storing collections of objects exposed by a WCF data service. This class inherits from ObservableCollection(Of T), which means that it implements the necessary infrastructure to send and receive notifications of changes over the items it contains. When the page is opened, a check is made to ensure that an instance of the service isn't already alive. The code accomplishes this with the first If block in the event handler. This is important if your app has more than one page and the page that interacts with the service can be opened at any time by the user, and it avoids generating a second instance if one already exists.
The next step is writing code that loads data. The code in Listing 4 is the same code we used for Windows Phone 7.5 in Part 4 of this series.
Listing 4Loading data asynchronously.
'Querying the data service for the full list of items 'and loading data asynchronously Private Sub loadCustomers() Dim query = From cust In Me.applicationData.Customers Order By cust.CompanyName Descending Select cust customers.LoadAsync(query) End Sub Private Sub loadOrders() orders.LoadAsync(New Uri("http://192.168.1.3/exposingodata/ApplicationData.svc/Orders", UriKind.Absolute)) End Sub Private Sub orders_LoadCompleted(sender As Object, e As LoadCompletedEventArgs) 'If the feed exposes paged data, load the next chunk of data If e.Error Is Nothing Then If Me.orders.Continuation IsNot Nothing Then Me.orders.LoadNextPartialSetAsync() Else 'Otherwise simply assign the data collection as the 'data source of the ContentPanel grid Me.ContentPanel.DataContext = Me.orders End If Else MessageBox.Show(e.Error.Message) End If End Sub Private Sub customers_LoadCompleted(sender As Object, e As LoadCompletedEventArgs) If e.Error Is Nothing Then 'No assignment of the customers collection 'because it will not be displayed in the UI If Me.customers.Continuation IsNot Nothing Then Me.customers.LoadNextPartialSetAsync() End If Else MessageBox.Show(e.Error.Message) End If End Sub
The final step is writing code that executes some operations over data, such as adding, removing, and saving orders. Listing 5 demonstrates this code.
Listing 5Executing data operations.
Private Sub InsertButton_Click(sender As Object, e As EventArgs) 'Hard coding the creation of a new order 'Assuming there is already a customer with the specified name Dim customerInstance = customers.Where(Function(c) _ c.CompanyName.ToLower.Contains("del sole")).FirstOrDefault Dim newOrder As New OrdersServiceReference.Order With newOrder .OrderDate = Date.Today .Description = "Order of Natural Water" .ShippedDate = Date.Today.AddDays(1) .RequiredDate = Date.Today.AddDays(2) .Customer = customerInstance End With Me.orders.Add(newOrder) End Sub Private Sub DeleteButton_Click(sender As Object, e As EventArgs) Dim currentOrder = TryCast(Me.OrdersListBox.SelectedItem, OrdersServiceReference.Order) If currentOrder IsNot Nothing Then Me.orders.Remove(currentOrder) End If End Sub Private Sub SaveButton_Click(sender As System.Object, e As System.EventArgs) 'Start saving asynchronously Me.applicationData.BeginSaveChanges(SaveChangesOptions.Batch, AddressOf OnChangesSaved, Me.applicationData) End Sub Private Sub OnChangesSaved(result As IAsyncResult) ''Use the dispatcher to run the operation inside the appropriate thread Dispatcher.BeginInvoke(Sub() 'Get the instance of the application data Me.applicationData = CType(result.AsyncState, ApplicationData) Try 'Finalize the save operation Me.applicationData.EndSaveChanges(result) 'Reload data for data-binding loadOrders() Catch ex As DataServiceRequestException MessageBox.Show(String.Format("Data service error: {0}", ex.Message)) Catch ex As Exception MessageBox.Show(String.Format("Error: {0}", ex.Message)) End Try End Sub) End Sub
The code simulates an insert operation by hard-coding a new instance of an order, rather than providing the user with the ability to specify one. This is intended to make the example simpler, but of course in real-world applications you would provide a specific page with textboxes and other controls.