Walkthrough: Consuming OData with MVVM for Windows Phone
March 23, 2012
In this walkthrough, you will build a simple application 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 applications 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 in a Windows Phone Application.
The application that you create in this walkthrough enables you to view Northwind data from the sample Northwind data service. We will create this application 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 application is available as a download from this MSDN Samples Gallery page.
In this walkthrough, you will perform the following tasks:
Modify the template-generated ViewModel to access the Northwind model
Maintain page state when navigating to and from your application
Use Application Bars to expose the save and cancel functionality
In the process, you will modify or create the following code files:
ViewModels\MainViewModel.cs: Modify the main ViewModel of the application to access data from the Northwind sample data service. The ViewModel also provides methods to save and restore application state and save changes to a read/write data service.
MainPage.xaml: Modify the main page of the application to update the existing StackPanel and Grid controls.
DetailsPage.xaml: Modify the details page of the application to update the existing Grid control that is the layout root for the page.
App.xaml.cs: Modify this file to create a static ViewModel that can be accessed across the application. SaveState and RestoreState methods are called to persist and restore application state during application state changes.
MainPage.xaml.cs: Modify this page to handle the cancel and refresh button clicks.
DetailsPage.xaml.cs: Modify this page to handle the save button click.
To complete this walkthrough, you must have Windows Phone SDK installed. For more information, see Installing the Windows Phone SDK.
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/Silverlight).
First, you create a new Windows Phone application project named MVVMODataTestApp. In later steps, you will add code to your application that assumes the application name is MVVMODataTestApp. If you choose a different name for your application, you must change the namespace references in the code.
To create the application project
-
In Visual Studio, on the File menu, point to New and then click Project.
The New Project dialog appears.
-
In the left pane, click Installed Templates, expand Visual C# or Visual Basic, and then click Silverlight for Windows Phone.
-
In the list of project types, click Windows Phone Databound Application.
-
In the Name box, type MVVMODataTestApp.
-
Click OK.
The New Windows Phone Application dialog appears.
-
Expand Target Windows Phone OS Version, click Windows Phone OS 7.1, and then click OK.
The new application project is created and opens in Visual Studio.
-
On the File menu, click Save All. (Ctrl+Shift+S)
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
Note:
Because the Windows Phone Databound Application project template includes an XML file that contains sample data, this project will execute before we make any changes. To see the behavior of the application using the sample data, on the Debug menu, click Start debugging. (F5)
-
In Solution Explorer, right-click the SampleData project and click Exclude From Project.
This removes the sample data file from the project. We are going to replace it with Northwind data from the data service.
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 application.
To add a data service reference to the project
-
Right-click the MVVMODataTestApp project, and then click Add Service Reference.
This displays the Add Service Reference dialog box.
-
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.
-
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 ODataNorthwindPhone.Northwind. A reference to the System.Data.Services.Client.dll assembly is also added.
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
In this procedure, you replace the code that defines the MainViewModel class generated from the project template with a version that instead exposes a typed DataServiceCollection<T>. This collection, which inherits from ObservableCollection, enables the ViewModel to notify its views when Customer objects in the collection change so that the views can update the user interface based on that change.
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 application state.
To update the ViewModel
-
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.
-
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 ViewModel : INotifyPropertyChanged { // Defines the root URI of the data service. // 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)); } } } }
-
On the File menu, click Save All. (Ctrl+Shift+S)
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
-
In Solution Explorer, right-click the MainPage.xaml file, and then click View Designer.
This opens the file for design and editing.
-
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.
-
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>
-
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="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Customers}" SelectionChanged="MainListBox_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> </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:
-
On the File menu, click Save All. (Ctrl+Shift+S)
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
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
-
In Solution Explorer, double-click the DetailsPage.xaml file.
This opens the file for design and editing.
-
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.
-
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.
-
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.
-
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) { 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.
-
On the File menu, click Save All. (Ctrl+Shift+S)
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
In this procedure, you add the code to maintain the page state. Applications are typically put into a dormant state when the user navigates away. In this state, the application is preserved in memory so that if the user returns to the application, it can resume almost instantly. This fast application switching is enabled automatically. However, it is still possible that an application will be terminated while it is dormant. It is important that you design your application so that it handles these changes in state that occur throughout the application lifecycle. For more information, see Execution Model for Windows Phone.
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 application to access this functionality to maintain the state of data in the ViewModel.
To maintain page state
-
In Solution Explorer, expand the ViewModels folder, right-click either the MainViewModel.cs or the MainViewModel.vb file, and then click View Code.
-
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; } }
-
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); } }
-
In Solution Explorer, right-click App.xaml and then click View Code.
The code-behind file opens in the code editor.
-
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.
-
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.
-
On the File menu, click Save All. (Ctrl+Shift+S)
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
In this application, 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 Application Bar of the MainPage and a Save button to the Application 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
-
In Solution Explorer, right-click the project MVVMTestApp, point to Add, and then click Existing Item.
The Add Existing Item dialog appears.
-
Browse to one of the following locations to locate the standard icons:
C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons\dark
C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark
-
Click the file appbar.save.rest.png, and then click Add.
-
Repeat steps 1-3 to also add the files appbar.cancel.rest.png and appbar.refresh.rest.png.
-
In Solution Explorer, select the new file appbar.save.rest.png.
-
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
-
Repeat steps 5-6 to set the following properties for the new file appbar.cancel.rest.png.
Property
Value
Build Action
Content
Copy to Output Directory
Copy if newer
File Name
AppBarCancel.png
-
Repeat steps 5-6 to set the following properties for the new file appbar.refresh.rest.png.
Property
Value
Build Action
Content
Copy to Output Directory
Copy if newer
File Name
AppBarRefresh.png
-
On the File menu, click Save All. (Ctrl+Shift+S)
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
To expose cancel, refresh, and save changes functionality in the MainViewModel
-
In Solution Explorer, expand the ViewModels folder, right-click either the MainViewModel.cs or the MainViewModel.vb file, and then click View Code.
-
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/Silverlight).
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; } -
On the File menu, click Save All. (Ctrl+Shift+S)
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
To add the Application Bars
-
In Solution Explorer, right-click MainPage.xaml and then click View Code.
The code-behind file opens in the code editor.
-
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(); } -
In Solution Explorer, right-click DetailsPage.xaml and then click View Code.
The code-behind file opens in the code editor.
-
In the DetailsPage class, add the following method:
-
In Solution Explorer, double-click MainPage.xaml to open the XAML in the designer.
-
Locate the sample Application Bar element, which is added to your project by default. It looks like the following:
<!--Sample code showing usage of ApplicationBar--> <!--<phone:PhoneApplicationPage.ApplicationBar> … </phone:PhoneApplicationPage.ApplicationBar>-->
-
Replace the sample Application Bar element with the following code:
<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> -
In Solution Explorer, double-click DetailsPage.xaml to open the XAML in the designer.
-
Locate the sample Application Bar element, which is added to your project by default. It looks like the following:
<!--Sample code showing usage of ApplicationBar--> <!--<phone:PhoneApplicationPage.ApplicationBar> … </phone:PhoneApplicationPage.ApplicationBar>-->
-
Replace the sample Application Bar element with the following code:
<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" > <shell:ApplicationBarIconButton IconUri="AppBarSave.png" Text="Save" Click="AppBarSave_Click" /> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> -
On the File menu, click Save All. (Ctrl+Shift+S)
-
On the Build menu, click Build Solution. (Ctrl+Shift+B)
In the following procedure, you test the application.
To run the application in the emulator
-
On the standard toolbar, set the deployment target of the application to Windows Phone Emulator (not Windows Phone Device).
-
On the Debug menu, click Start Without Debugging.
The emulator opens, and then the application starts.