Walkthrough: Consuming OData with MVVM for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

In this walkthrough, you will build a simple app that implements the Model-View-ViewModel (MVVM) design pattern to access a data service that implements the Open Data Protocol (OData). MVVM is a way to separate your data from your user interface, which is important for apps that consume OData feeds. In this sample, the data model is a set of proxy classes generated by consuming the sample Northwind data service, and the view is a XAML user control. The ViewModel, which is the link between the data model and the user interface, will be a C# class that uses the OData Client Library for Windows Phone. For more information about the MVVM design pattern, see Implementing the Model-View-ViewModel pattern for Windows Phone 8. The OData client for Windows Phone is not part of the Windows Phone SDK and must be downloaded separately from WCF Data Services Tools for Visual Studio

The app that you create in this walkthrough enables you to view Northwind data from the sample Northwind data service. We will create this app by using the Windows Phone Databound Application template as a starting point, and we will replace the sample data provided by the template with Northwind data from the OData service. A completed version of this app is available as a download from this MSDN Samples Gallery page.

In this walkthrough, you will perform the following tasks:

  • Create the Windows Phone databound application

  • Use the client library to create the Northwind-based model

  • Modify the template-generated ViewModel to access the Northwind model

  • Modify the application pages to use our ViewModel

  • Maintain page state when navigating to and from your application

  • Use Application Bars to expose the save and cancel functionality

  • Run the completed application

In the process, you will modify or create the following code files:

  1. ViewModels\MainViewModel.cs: Modify the main ViewModel of the app to access data from the Northwind sample data service. The ViewModel also provides methods to save and restore app state and save changes to a read/write data service.

  2. MainPage.xaml: Modify the main page of the app to update the existing StackPanel and Grid controls.

  3. DetailsPage.xaml: Modify the details page of the app to update the existing Grid control that is the layout root for the page.

  4. App.xaml.cs: Modify this file to create a static ViewModel that can be accessed across the app. SaveState and RestoreState methods are called to persist and restore app state during app state changes.

  5. MainPage.xaml.cs: Modify this page to handle the cancel and refresh button clicks.

  6. DetailsPage.xaml.cs: Modify this page to handle the save button click.

Prerequisites

To complete this walkthrough, you must have Windows Phone SDK installed. For more information, see Get the SDK.

You must also install the OData client for Windows Phone which is available here: WCF Data Services Tools for Visual Studio.

This walkthrough uses the Northwind sample data service that is published on the OData website. This sample data service is read-only; attempting to save changes will return an error. To complete the final section of this walkthrough that saves changes to the Northwind data service, you must implement your own read/write version of the Northwind data service. You can do this by completing the procedures in the topic How to: Create the Northwind Data Service (WCF Data Services).

Creating the app project

First, you create a new Windows Phone app project named MVVMODataTestApp. In later steps, you will add code to your app that assumes the app name is MVVMODataTestApp. If you choose a different name for your app, you must change the namespace references in the code.

To create the app project

  1. In Visual Studio, on the File menu, point to New and then click Project.

    The New Project dialog appears.

  2. In the left pane, make sure the Templates item is expanded and select Visual C# or Visual Basic. Visual Basic is located under Other Languages.

  3. In the list of project types, click Windows Phone Databound App.

  4. In the Name box, type MVVMODataTestApp.

  5. Click OK.

    The Windows Phone platform selection dialog box appears.

  6. Expand Target Windows Phone OS Version, click Windows Phone OS 8.0, and then click OK.

    The new app project is created and opens in Visual Studio.

  7. On the Build menu, click Build Solution. (Ctrl+Shift+B)

Note

Because the Windows Phone Databound App project template includes an XAML file that contains sample data, this project will execute before we make any changes. To see the behavior of the app using the sample data, on the Debug menu, click Start debugging. (F5)

  1. In Solution Explorer, right-click the SampleData folder and click Exclude From Project.

    This removes the sample data folder from the project. We are going to replace it with Northwind data from the data service.

Creating the Northwind data model

In this procedure, you add a reference to the Northwind sample data service. When you use the Add Service Reference tool in Visual Studio, the tool generates a set of client data classes that represents the data model of the Northwind data service. These classes are the Model of the MVVM pattern for this app.

To add a data service reference to the project

  1. Right-click the MVVMODataTestApp project, and then click Add Service Reference.

    This displays the Add Service Reference dialog box.

  2. In the Address text box, enter the following URI value and then click Go:

    http://services.odata.org/Northwind/Northwind.svc/
    

    This downloads the metadata document from the public, read-only Northwind sample data service.

    If you are using your own read/write implementation of the Northwind data service, you must instead supply the URI value to this service. When the project for the custom Northwind data service is in the same solution as the MVVMODataTestApp sample project, click the Discover button to discover the URI of the Northwind data service.

  3. In the Namespace text box, type Northwind, and then click OK.

    This adds a new code file to the project, which contains the data classes that are used to access and interact with data service resources as objects. The data classes are created in the namespace MVVMODataTestApp.Northwind. A reference to the System.Data.Services.Client.WP80.dll assembly is also added.

  4. On the Build menu, click Build Solution. (Ctrl+Shift+B)

Updating the MainViewModel

In this procedure, you replace the code that defines the MainViewModel class generated from the project template with a version that exposes a typed DataServiceCollection. This collection, which inherits from ObservableCollection<(Of <(T>)>), enables the ViewModel to notify its views when Customer objects in the collection change so the views can update the user interface.

The MainViewModel also contains the code to query the data service to load Customer data into the collection. In a later procedure, you will add other methods that expose functionality of the OData client library required to save changes, cancel a request, and store app state.

To update the ViewModel

  1. In Solution Explorer, expand the ViewModels folder, right-click either the MainViewModel.cs or the MainViewModel.vb file, and then click View Code.

    This displays the code file.

  2. Replace the code for MainViewModel class with the following code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data.Services.Client;
    using System.Linq;
    using System.Windows;
    using MVVMODataTestApp.Northwind;
    
    namespace MVVMODataTestApp
    {
        public class MainViewModel : INotifyPropertyChanged
        {
    
            // This is the URI of the public, read-only Northwind data service. 
            // To make updates and save changes, replace this URI 
            // with your own Northwind service implementation.
            private static readonly Uri _rootUri = 
                new Uri("http://services.odata.org/Northwind/Northwind.svc/");
    
            // Define the typed DataServiceContext.
            private NorthwindEntities _context;
    
            // Define the binding collection for Customers.
            private DataServiceCollection<Customer> _customers;
    
            // Gets and sets the collection of Customer objects from the feed.
            // This collection is used to bind to the UI (View).
            public DataServiceCollection<Customer> Customers
            {
                get { return _customers; }
    
                private set
                {
                    // Set the Titles collection.
                    _customers = value;
    
                    // Register a handler for the LoadCompleted callback.
                    _customers.LoadCompleted += OnCustomersLoaded;
    
                    // Raise the PropertyChanged events.
                    NotifyPropertyChanged("Customers");
                }
            }
    
            // Used to determine whether the data is loaded.
            public bool IsDataLoaded { get; private set; }
    
            // Loads data when the application is initialized.
            public void LoadData()
            {
                // Instantiate the context and binding collection.
                _context = new NorthwindEntities(_rootUri);
                Customers = new DataServiceCollection<Customer>(_context);
    
                // Specify an OData query that returns all customers.
                var query = from cust in _context.Customers
                            select cust;
    
                // Load the customer data.
                Customers.LoadAsync(query);
            }
    
            // Displays data from the stored data context and binding collection 
            public void LoadData(NorthwindEntities context,
                DataServiceCollection<Customer> _customers)
            {
                _context = context;
                Customers = _customers;
    
                IsDataLoaded = true;
            }
    
            // Handles the DataServiceCollection<T>.LoadCompleted event.
            private void OnCustomersLoaded(object sender, LoadCompletedEventArgs e)
            {
                // Make sure that we load all pages of the Customers feed.
                if (Customers.Continuation != null)
                {
                    Customers.LoadNextPartialSetAsync();
                }
                IsDataLoaded = true;
            }
    
            // Declare a PropertyChanged for the UI to register 
            // to get updates from the ViewModel.
            public event PropertyChangedEventHandler PropertyChanged;
    
            // Notifies the binding about a changed property value.
            private void NotifyPropertyChanged(string propertyName)
            {
                var propertyChanged = PropertyChanged;
                if (propertyChanged != null)
                {
                    // Raise the PropertyChanged event.
                    propertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
    
  3. On the File menu, click Save All. (Ctrl+Shift+S)

Updating the Main Page

In this procedure, you will update the MainPage.xaml file generated from the project template to makes sure that the view in this page, which is a ListBox control, is bound to the Customers property exposed by our MainViewModel.

To update the MainPage.xaml file

  1. In Solution Explorer, right-click the MainPage.xaml file, and then click View Designer.

    This opens the file for design and editing.

  2. In the top-level phone element, remove the d:DataContext element.

    We need to do this because the MainViewModelSampleData.xaml sample data file is no longer available for binding during design.

  3. Locate the StackPanel element named TitlePanel and replace it with the following code:

    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
                <TextBlock x:Name="ApplicationTitle" Text="NORTHWIND TRADERS" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="Customers" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
  4. Locate the Grid element named ContentPanel and replace it with the following code:

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <ListBox x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding Customers}" SelectionChanged="MainLongListSelector_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="0,0,0,17" Width="432" Height="100">
                        <TextBlock Text="{Binding CompanyName}" TextWrapping="NoWrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                        <TextBlock Text="{Binding ContactName}" TextWrapping="NoWrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
                        <TextBlock Text="{Binding Phone}" TextWrapping="NoWrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
    

    The ListBox (view) is bound to the Customers property of the MainViewModel class, with individual controls in the ItemTemplate bound to properties of Customer objects in the collection. Note that the top-level binding is defined in the project template in the code-behind page for the MainPage.xaml file by this line of code:

    // Set the data context of the listbox control to the sample data.
    DataContext = App.ViewModel;
    
  5. On the File menu, click Save All. (Ctrl+Shift+S)

To update the MainPage.xaml.cs code behind page

  • Update the MainLongListSelector_SelectionChanged method with the following code.

    // Handle selection changed on LongListSelector
    private void MainLongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // If selected item is null (no selection) do nothing
        if (MainLongListSelector.SelectedItem == null)
        return;
    
        // Navigate to the new page
        NavigationService.Navigate(new Uri("/DetailsPage.xaml?selectedItem=" + MainLongListSelector.SelectedIndex , UriKind.Relative));
    
        // Reset selected item to null (no selection)
        MainLongListSelector.SelectedItem = null;
    }
    

    Here, we are modifying the call to NavigationService.Navigate to use the index of the selected item, rather than the ID of the ItemViewModel, since we are not using the ItemViewModel class in this sample.

Updating the Details Page

In this procedure, you will update both the DetailsPage.xaml and code-behind files generated from the project template to make sure that the elements in this page are bound to the Customer object selected in the ListView control in MainPage.xml.

To update the DetailsPage.xaml and code-behind pages

  1. In Solution Explorer, double-click the DetailsPage.xaml file.

    This opens the file for design and editing.

  2. In the top-level phone element, remove the d:DataContext element.

    We need to do this because the MainViewModelSampleData.xaml sample data file is no longer available for binding during design.

  3. Locate the Grid element named LayoutRoot and replace it with the following code:

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="PageTitle" Text="NORTHWIND TRADERS" 
                        Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="ListTitle" Text="{Binding CompanyName}" Margin="9,-7,0,0" 
                        Style="{StaticResource PhoneTextTitle1Style}" />
        </StackPanel>
        <ScrollViewer Grid.Row="1">
            <Grid x:Name="ContentPanel" Margin="12,0,12,0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="165"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="Contact name:" Style="{StaticResource PhoneTextNormalStyle}" 
                        VerticalAlignment="Center" Grid.Row="0" Grid.Column="0"/>
                <TextBlock Text="Contact title:" Style="{StaticResource PhoneTextNormalStyle}" 
                        VerticalAlignment="Center" Grid.Row="1" Grid.Column="0"/>
                <TextBlock Text="Phone number:" Style="{StaticResource PhoneTextNormalStyle}" 
                        VerticalAlignment="Center" Grid.Row="2" Grid.Column="0"/>
                <TextBlock Text="Address:" Style="{StaticResource PhoneTextNormalStyle}" 
                        VerticalAlignment="Center" Grid.Row="3" Grid.Column="0"/>
                <TextBlock Text="City:" Style="{StaticResource PhoneTextNormalStyle}" 
                        VerticalAlignment="Center" Grid.Row="4" Grid.Column="0"/>
                <TextBlock Text="Region:" Style="{StaticResource PhoneTextNormalStyle}" 
                        VerticalAlignment="Center" Grid.Row="5" Grid.Column="0"/>
                <TextBlock Text="Postal code:" Style="{StaticResource PhoneTextNormalStyle}" 
                        VerticalAlignment="Center" Grid.Row="6" Grid.Column="0"/>
                <TextBox Text="{Binding ContactName, Mode=TwoWay}" Grid.Row="0" Grid.Column="1"/>
                <TextBox Text="{Binding ContactTitle, Mode=TwoWay}" Grid.Row="1" Grid.Column="1"/>
                <TextBox Text="{Binding Phone, Mode=TwoWay}" Grid.Row="2" Grid.Column="1"/>
                <TextBox Text="{Binding Address, Mode=TwoWay}" Grid.Row="3" Grid.Column="1"/>
                <TextBox Text="{Binding City, Mode=TwoWay}" Grid.Row="4" Grid.Column="1"/>
                <TextBox Text="{Binding Region, Mode=TwoWay}" Grid.Row="5" Grid.Column="1"/>
                <TextBox Text="{Binding PostalCode, Mode=TwoWay}" Grid.Row="6" Grid.Column="1"/>
            </Grid>
        </ScrollViewer>
    </Grid>
    

    This code contains the TextBox controls (views) that are bound to properties of the Customer object selected in the MainViewModel. The binding is two-way to enable updates when accessing a read-write version of the Northwind data service.

  4. In Solution Explorer, right-click either the DetailsPage.xaml.cs or DetailsPage.xaml.vb file, and then click View Code.

    This opens the file for editing.

  5. Locate the OnNavigatedTo method implementation, and replace it with the following code:

    // When the page is navigated to, set the data context 
    // to the selected item in the list.
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    
     if (DataContext == null)
                {
                    string selectedIndex = "";
                    if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
                    {
                        int index = int.Parse(selectedIndex);
                        DataContext = App.ViewModel.Customers[index];
                    }
                }
    
    
    
    
    
    }
    

    This sets the binding context of the view to the currently selected Customer, exposed by the MainViewModel.

  6. On the File menu, click Save All. (Ctrl+Shift+S)

  7. On the Build menu, click Build Solution. (Ctrl+Shift+B)

Maintaining page state

In this procedure, you add the code to maintain the page state. Apps are typically put into a dormant state when the user navigates away. In this state, the app is preserved in memory so that if the user returns to the app, it can resume almost instantly. This fast app switching is enabled automatically. However an app can be terminated while it is dormant. It is important that you design your app so that it handles these state changes . For more information, seeApp activation and deactivation for Windows Phone 8.

The OData client for Windows Phone includes a DataServiceState class that is used to help manage these state transitions. The ViewModel must also expose methods that enable the app to access this functionality to maintain the state of data in the ViewModel.

To maintain page state

  1. In Solution Explorer, expand the ViewModels folder, right-click either the MainViewModel.cs or the MainViewModel.vb file, and then click View Code.

  2. In the MainViewModel class, add the following SaveState method:

    // Return a string serialization of the application state.
    public string SaveState()
    {
        if (App.ViewModel.IsDataLoaded)
        {
            // Create a new dictionary to store binding collections. 
            var collections = new Dictionary<string, object>();
    
            // Add the current Customers binding collection.
            collections["Customers"] = Customers;
    
            // Return the serialized context and binding collections.
            return DataServiceState.Serialize(_context, collections);
        }
        else
        {
            return string.Empty;
        }
    }
    
  3. In the MainViewModel class, add the following RestoreState method:

    // Restores the view model state from the supplied state serialization.
    public void RestoreState(string appState)
    {
        // Create a dictionary to hold any stored binding collections.
        Dictionary<string, object> collections;
    
        if (!string.IsNullOrEmpty(appState))
        {
            // Deserialize the DataServiceState object.
            DataServiceState state
                = DataServiceState.Deserialize(appState);
    
            // Restore the context and binding collections.
            var context = state.Context as NorthwindEntities;
            collections = state.RootCollections;
    
            // Get the binding collection of Customer objects.
            DataServiceCollection<Customer> customers
                = collections["Customers"] as DataServiceCollection<Customer>;
    
            // Initialize the application with stored data. 
            App.ViewModel.LoadData(context, customers);
        }
    }
    
  4. In Solution Explorer, right-click App.xaml and then click View Code.

    The code-behind file opens in the code editor.

  5. Locate the Application_Deactivated method and replace it with the following code:

    // Code to execute when the application is deactivated (sent to the background).
    // This code will not execute when the application is closing.
    private void Application_Deactivated(object sender, DeactivatedEventArgs e)
    {
        if (App.ViewModel.IsDataLoaded)
        {
            // Store application state in the state dictionary.              
            PhoneApplicationService.Current.State["ApplicationState"]
                = ViewModel.SaveState();
        }
    }
    

    This code calls the SaveState method on the ViewModel, which returns a string that is the serialization of the DataServiceState object.

  6. Locate the Application_Activated method and replace it with the following code:

    // Code to execute when the application is activated (brought to the foreground).
    // This code will not execute when the application is first launched.
    private void Application_Activated(object sender, ActivatedEventArgs e)
    {
        // If data is not still loaded, try to get it from the state store.
        if (!ViewModel.IsDataLoaded)
        {
            if (PhoneApplicationService.Current.State.ContainsKey("ApplicationState"))
            {
                // Get back the serialized data service state from the dictionary.
                string appState =
                    PhoneApplicationService.Current.State["ApplicationState"]
                    as string;
    
                // Use the returned dictionary to restore the state of the data service.
                App.ViewModel.RestoreState(appState);
            }
            else
            {
                // Load the data since it is not persisted in the state dictionary. 
                App.ViewModel.LoadData();
            }
        }
    }
    

    This code calls the RestoreState method on the ViewModel with the serialized DataServiceState object from the state dictionary. When this string is not available in the state dictionary, the data is loaded from the data service instead.

  7. On the File menu, click Save All. (Ctrl+Shift+S)

  8. On the Build menu, click Build Solution. (Ctrl+Shift+B)

Adding the app bar

In this app, the user can cancel a LoadAsync()()() operation by tapping a Cancel button or reload the data from the data service by tapping a Refresh button. The user also chooses when they want to send updates made to customer details data (to a read/write data service) by tapping a Save button. In this procedure, you add Cancel and Refresh buttons to the app bar of the MainPage and a Save button to the app bar of the DetailPage. These functionalities of the DataServiceContext class are exposed as methods of the MainViewModel.

Important Note:

Saving changes will cause an error when accessing the public read-only Northwind sample data service. You must create your own read/write version of the Northwind sample data service to save changes to the data service. You must also make sure that the Customers feed in your customer Northwind data service is writable. Do this by changing the EntitySetRights value passed to the SetEntitySetAccessRule data service’s configuration method to EntitySetRights.AllRead.

For the button’s icon, you will use one of the standard Windows Phone icons. For more information, see Application Bar for Windows Phone.

To add the icon files

  1. In Solution Explorer, right-click the project MVVMTestApp, point to Add, and then click Existing Item.

    The Add Existing Item dialog appears.

  2. Browse to the following location to locate the standard icons:

    C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v8.0\Icons\dark

  3. Select the save icon, and then click Add.

  4. Repeat steps 1-3 to also add the cancel and refresh icons.

  5. In Solution Explorer, select the new file save.png.

  6. In the Properties window, set the following properties for the new file.

Property

Value

Build Action

Content

Copy to Output Directory

Copy if newer

File Name

AppBarSave.png

  1. Repeat steps 5-6 to set the following properties for the new file cancel.png.

Property

Value

Build Action

Content

Copy to Output Directory

Copy if newer

File Name

AppBarCancel.png

  1. Repeat steps 5-6 to set the following properties for the new file refresh.png.

Property

Value

Build Action

Content

Copy to Output Directory

Copy if newer

File Name

AppBarRefresh.png

  1. On the File menu, click Save All. (Ctrl+Shift+S)

  2. On the Build menu, click Build Solution. (Ctrl+Shift+B)

To expose cancel, refresh, and save changes functionality in the MainViewModel

  1. In Solution Explorer, expand the ViewModels folder, right-click either the MainViewModel.cs or the MainViewModel.vb file, and then click View Code.

  2. In the MainViewModel class, add the following methods that cancel the LoadAsync()()() operation, reload data from the data service, and asynchronously send changes to the data service:

    public void CancelCustomersAsyncLoad()
    {
        // Call the CancelAsyncLoad method on the binding collection.
        this.Customers.CancelAsyncLoad();
    }
    
    public void SaveChanges()
    {
        // Start the save changes operation. 
        this._context.BeginSaveChanges(OnChangesSaved, this._context);
    }
    
    private void OnChangesSaved(IAsyncResult result)
    {
        // Use the Dispatcher to ensure that the 
        // asynchronous call returns in the correct thread.
        Deployment.Current.Dispatcher.BeginInvoke(() =>
        {
            this._context = result.AsyncState as NorthwindEntities;
    
            try
            {
                // Complete the save changes operation.
                this._context.EndSaveChanges(result);
            }
            catch (DataServiceRequestException ex)
            {
                // Ideally, we should not create a UI element 
                // from the ViewModel. A better way is to use a 
                // service or event to report exceptions to the view.
                MessageBox.Show(string.Format(
                        "{0} The target Northwind data service ('{1}') is read-only.",
                        ex.Message, this._context.BaseUri));
            }
        }
        );
    }
    
Important Note:

Saving changes will cause an error when accessing the public read-only Northwind sample data service. During regular execution, the client library raises a DataServiceRequestException that is handled to display a message box. When attempting to save changes to the read-only data service during debugging, an unhandled exception occurs because of a bug in the client library. To implement your own read/write version of the Northwind data service, complete the procedures in the topic How to: Create the Northwind Data Service (WCF Data Services).

``` csharp public void Refresh() { // Cache the current merge option and change // it to MergeOption.OverwriteChanges. MergeOption cachedOption = _context.MergeOption; _context.MergeOption = MergeOption.OverwriteChanges; // Reload data from the data service. this.LoadData(); // Reset the merge option. _context.MergeOption = cachedOption; } ```
  1. On the File menu, click Save All. (Ctrl+Shift+S)

  2. On the Build menu, click Build Solution. (Ctrl+Shift+B)

To add the app bars

  1. In Solution Explorer, right-click MainPage.xaml and then click View Code.

    The code-behind file opens in the code editor.

  2. In the MainPage class, add the following methods:

    private void AppBarCancel_Click(object sender, EventArgs e)
    {
        App.ViewModel.CancelCustomersAsyncLoad();
    }
    
    private void AppBarRefresh_Click(object sender, EventArgs e)
    {
        // Reload the data from the OData service.
        App.ViewModel.Refresh();
    }
    
  3. In Solution Explorer, right-click DetailsPage.xaml and then click View Code.

    The code-behind file opens in the code editor.

  4. In the DetailsPage class, add the following method:

    private void AppBarSave_Click(object sender, EventArgs e)
    {
        App.ViewModel.SaveChanges();
    }
    
  5. In Solution Explorer, double-click MainPage.xaml to open the XAML in the designer.

  6. Add the following app bar element after the LayoutRoot</Grid> tag

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" >
                <shell:ApplicationBarIconButton IconUri="AppBarRefresh.png" 
                            Text="Refresh" Click="AppBarRefresh_Click" />
                <shell:ApplicationBarIconButton IconUri="AppBarCancel.png" 
                            Text="Cancel" Click="AppBarCancel_Click" />
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
    
  7. In Solution Explorer, double-click DetailsPage.xaml to open the XAML in the designer.

  8. Add the following app bar element after the LayoutRoot</Grid> tag

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" >
            <shell:ApplicationBarIconButton IconUri="AppBarSave.png" 
                        Text="Save" Click="AppBarSave_Click" />
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
    
  9. On the File menu, click Save All. (Ctrl+Shift+S)

  10. On the Build menu, click Build Solution. (Ctrl+Shift+B)

Testing the app

In the following procedure, you test the app.

To run the app in the emulator

  1. On the standard toolbar, set the deployment target of the app to Windows Phone Emulator (not Windows Phone Device).

  2. On the Debug menu, click Start Without Debugging.

    The emulator opens, and the app starts.

See Also

Other Resources

OData client for Windows Phone 8

How to consume an OData service for Windows Phone 8

How to persist the state of an OData client for Windows Phone 8