Freigeben über


Azure Mobile Services QuickStart for WPF

One of the great features in my opinion of Azure Mobile Services is the “quickstart” app – a ready-to-use, fully-functional application which you can get from the portal in many of the supported platforms, and start running right away. I find it to be a great way to learn about the service and the client SDK for the selected platform.

00-Quickstart

In the portal one can download a QuickStart app for the most used platforms. But every once in a while someone asks about another platform which is not in the list. Since not all platforms will make its way to the portal (unless there is strong demand for that), I’ll try to answer that question, specifically about WPF, with this post.

Creating the QuickStart app for WPF isn’t too hard – after all, the NuGet package with the client SDK for Azure Mobile Services actually supports WPF apps as well (as long as they target the .NET Framework 4.5). It has most of the functionality as the more prominent platforms, with the notable exception of the lack of the UI-based login feature (which can be implemented as an extension, as I’ve shown in another post). So, without further ado, here are the steps I took to create the app.

If you only want to download the project and skip the process, you can go ahead to the Code Gallery sample.

Create a new WPF project

Make sure that the framework is set to 4.5.

01-CreateWPFProject

Add reference to the Azure Mobile Services SDK

Right-click on the project itself, or in the References link, then select “Manage NuGet Packages…” (make sure that you have the latest version of the NuGet Package Manager – check the “Tools –> Extensions and Updates” menu)

02-ManageNuGetPackages

On the package manager, type “mobileservices” in the search box, then search online for the “Windows Azure Mobile Services” package, and click the “Install” button.

03-WindowsAzure.MobileServicesPackage

Setting up the UI

At this point we have an empty WPF application. Since both WPF and the Windows Store use XAML as their UI framework, I decided to download the QuickStart for the Windows Store app for my mobile service, and use it as a template. The first thing I noticed is that it uses a custom user control to display some caption, inside the “Common” folder. So let’s replicate it here as well.

04-NewFolderCommon

And inside that folder, let’s add a new user control. Name the control QuickStartTask.xaml.

05-NewUserControl

Open the QuickStartTask.xaml, and copy the following code over the <Grid> declaration (which I copied from the Windows Store quickstart):

  1. <Grid VerticalAlignment="Top">
  2.     <StackPanel Orientation="Horizontal">
  3.         <Border BorderThickness="0,0,1,0" BorderBrush="DarkGray" Margin="0,10" MinWidth="70">
  4.             <TextBlock Text="{Binding Number}" FontSize="45" Foreground="DarkGray" Margin="20,0"/>
  5.         </Border>
  6.         <StackPanel>
  7.             <TextBlock Text="{Binding Title}" Margin="10,10,0,0" FontSize="16" FontWeight="Bold"/>
  8.             <TextBlock Text="{Binding Description}" Margin="10,0,0,0" TextWrapping="Wrap" MaxWidth="500" />
  9.         </StackPanel>
  10.     </StackPanel>
  11. </Grid>

And do the same for the QuickStartTask.xaml.cs – replace the class contents with the code below (again, copied verbatim from the Windows Store quickstart):

  1. public QuickStartTask()
  2. {
  3.     this.InitializeComponent();
  4.     this.DataContext = this;
  5. }
  6.  
  7. public int Number
  8. {
  9.     get { return (int)GetValue(NumberProperty); }
  10.     set { SetValue(NumberProperty, value); }
  11. }
  12.  
  13. // Using a DependencyProperty as the backing store for Number.  This enables animation, styling, binding, etc...
  14. public static readonly DependencyProperty NumberProperty =
  15.     DependencyProperty.Register("Number", typeof(int), typeof(QuickStartTask), new PropertyMetadata(0));
  16.  
  17. public string Title
  18. {
  19.     get { return (string)GetValue(TitleProperty); }
  20.     set { SetValue(TitleProperty, value); }
  21. }
  22.  
  23. // Using a DependencyProperty as the backing store for Title.  This enables animation, styling, binding, etc...
  24. public static readonly DependencyProperty TitleProperty =
  25.     DependencyProperty.Register("Title", typeof(string), typeof(QuickStartTask), new PropertyMetadata(default(string)));
  26.  
  27.  
  28. public string Description
  29. {
  30.     get { return (string)GetValue(DescriptionProperty); }
  31.     set { SetValue(DescriptionProperty, value); }
  32. }
  33.  
  34. // Using a DependencyProperty as the backing store for Description.  This enables animation, styling, binding, etc...
  35. public static readonly DependencyProperty DescriptionProperty =
  36.     DependencyProperty.Register("Description", typeof(string), typeof(QuickStartTask), new PropertyMetadata(default(string)));

You should be able to build your solution at this point to make sure that everything is ok. Now with the custom user control ready, we can start defining the main page of the WPF app. In the Windows Store app, that page is defined in the MainPage.xaml[.cs], while in the WPF, I’ll use the MainWindow.xaml[.cs]. First, update the title / height / width properties of the window so that the elements will show up nice as if it was a full-screen Windows Store app. Also, we need to define a XML namespace for the user control which we created before. In the code below, it’s defined with the ‘local’ prefix.

  1. <Window x:Class="WPFQuickStart.MainWindow"
  2.         xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  4.         xmlns:local="clr-namespace:WPFQuickStart.Common"
  5.         Title="Azure Mobile Serivces QuickStart" Height="768" Width="1280">

And after that, the body of the XAML. Copy the XML below on top of the empty <Grid> element in the MainWindow.xaml page. Notice that this was copied exactly from the Windows Store MainPage.xaml file, with the exception of the service name (which I replaced with a generic ‘YOUR-SERVICE-NAME’).

  1. <Grid Background="White">
  2.  
  3.     <Grid Margin="50,50,10,10">
  4.         <Grid.ColumnDefinitions>
  5.             <ColumnDefinition Width="*" />
  6.             <ColumnDefinition Width="*" />
  7.         </Grid.ColumnDefinitions>
  8.         <Grid.RowDefinitions>
  9.             <RowDefinition Height="Auto" />
  10.             <RowDefinition Height="*" />
  11.         </Grid.RowDefinitions>
  12.  
  13.         <Grid Grid.Row="0" Grid.ColumnSpan="2" Margin="0,0,0,20">
  14.             <StackPanel>
  15.                 <TextBlock Foreground="#0094ff" FontFamily="Segoe UI Light" Margin="0,0,0,6">WINDOWS AZURE MOBILE SERVICES</TextBlock>
  16.                 <TextBlock Foreground="Gray" FontFamily="Segoe UI Light" FontSize="45" >YOUR-SERVICE-NAME</TextBlock>
  17.             </StackPanel>
  18.         </Grid>
  19.  
  20.         <Grid Grid.Row="1">
  21.             <StackPanel>
  22.  
  23.                 <local:QuickStartTask Number="1" Title="Insert a TodoItem" Description="Enter some text below and click Save to insert a new todo item into your database" />
  24.  
  25.                 <StackPanel Orientation="Horizontal" Margin="72,0,0,0">
  26.                     <TextBox Name="TextInput" Margin="5" MinWidth="300"></TextBox>
  27.                     <Button Name="ButtonSave" Click="ButtonSave_Click">Save</Button>
  28.                 </StackPanel>
  29.  
  30.             </StackPanel>
  31.         </Grid>
  32.  
  33.         <Grid Grid.Row="1" Grid.Column="1">
  34.             <Grid.RowDefinitions>
  35.                 <RowDefinition Height="Auto" />
  36.                 <RowDefinition />
  37.             </Grid.RowDefinitions>
  38.             <StackPanel>
  39.                 <local:QuickStartTask Number="2" Title="Query and Update Data" Description="Click refresh below to load the unfinished TodoItems from your database. Use the checkbox to complete and update your TodoItems" />
  40.                 <Button Margin="72,0,0,0" Name="ButtonRefresh" Click="ButtonRefresh_Click">Refresh</Button>
  41.             </StackPanel>
  42.  
  43.             <ListView Name="ListItems" Margin="62,10,0,0" Grid.Row="1">
  44.                 <ListView.ItemTemplate>
  45.                     <DataTemplate>
  46.                         <StackPanel Orientation="Horizontal">
  47.                             <CheckBox Name="CheckBoxComplete" IsChecked="{Binding Complete, Mode=TwoWay}" Checked="CheckBoxComplete_Checked" Content="{Binding Text}" Margin="10,5" VerticalAlignment="Center"/>
  48.                         </StackPanel>
  49.                     </DataTemplate>
  50.                 </ListView.ItemTemplate>
  51.             </ListView>
  52.  
  53.         </Grid>
  54.  
  55.     </Grid>
  56. </Grid>

Some of the items in the XAML above also require a reference which I didn’t have by default (System.Windows.dll), so if this is the case in your project, add it as well.

Implementing the class

The XAML above defines some event handlers (button click, checkbox checked) which need to be implemented. As before, here’s the code for the MainWindow.cs. This is copied from the Windows Store version, and the only changes are the call to the message dialog (the usage of the MessageDialog class in the store app was replaced with a call to MessageBox.Show) and the OnNavigatedTo override was replaced by the OnActivated in the WPF app).

  1. public class TodoItem
  2. {
  3.     public int Id { get; set; }
  4.  
  5.     [JsonProperty(PropertyName = "text")]
  6.     public string Text { get; set; }
  7.  
  8.     [JsonProperty(PropertyName = "complete")]
  9.     public bool Complete { get; set; }
  10. }
  11.  
  12. public partial class MainWindow : Window
  13. {
  14.     private MobileServiceCollection<TodoItem, TodoItem> items;
  15.     private IMobileServiceTable<TodoItem> todoTable = App.MobileService.GetTable<TodoItem>();
  16.  
  17.     public MainWindow()
  18.     {
  19.         InitializeComponent();
  20.     }
  21.  
  22.     private async void InsertTodoItem(TodoItem todoItem)
  23.     {
  24.         // This code inserts a new TodoItem into the database. When the operation completes
  25.         // and Mobile Services has assigned an Id, the item is added to the CollectionView
  26.         await todoTable.InsertAsync(todoItem);
  27.         items.Add(todoItem);
  28.     }
  29.  
  30.     private async void RefreshTodoItems()
  31.     {
  32.         MobileServiceInvalidOperationException exception = null;
  33.         try
  34.         {
  35.             // This code refreshes the entries in the list view by querying the TodoItems table.
  36.             // The query excludes completed TodoItems
  37.             items = await todoTable
  38.                 .Where(todoItem => todoItem.Complete == false)
  39.                 .ToCollectionAsync();
  40.         }
  41.         catch (MobileServiceInvalidOperationException e)
  42.         {
  43.             exception = e;
  44.         }
  45.  
  46.         if (exception != null)
  47.         {
  48.             MessageBox.Show(exception.Message, "Error loading items");
  49.         }
  50.         else
  51.         {
  52.             ListItems.ItemsSource = items;
  53.         }
  54.     }
  55.  
  56.     private async void UpdateCheckedTodoItem(TodoItem item)
  57.     {
  58.         // This code takes a freshly completed TodoItem and updates the database. When the MobileService
  59.         // responds, the item is removed from the list
  60.         await todoTable.UpdateAsync(item);
  61.         items.Remove(item);
  62.     }
  63.  
  64.     private void ButtonRefresh_Click(object sender, RoutedEventArgs e)
  65.     {
  66.         RefreshTodoItems();
  67.     }
  68.  
  69.     private void ButtonSave_Click(object sender, RoutedEventArgs e)
  70.     {
  71.         var todoItem = new TodoItem { Text = TextInput.Text };
  72.         InsertTodoItem(todoItem);
  73.     }
  74.  
  75.     private void CheckBoxComplete_Checked(object sender, RoutedEventArgs e)
  76.     {
  77.         CheckBox cb = (CheckBox)sender;
  78.         TodoItem item = cb.DataContext as TodoItem;
  79.         UpdateCheckedTodoItem(item);
  80.     }
  81.  
  82.     protected override void OnActivated(EventArgs e)
  83.     {
  84.         RefreshTodoItems();
  85.     }
  86. }

Make sure that you have all necessary “import” statements (Newtonsoft.Json and Microsoft.WindowsAzure.MobileServices). Now the only thing remaining is the declaration of the mobile service client itself. Open the file App.xaml.cs and insert this declaration (it can be copied from the portal itself, in the section about “connect an existing app” in the QuickStart page):

  1. public static MobileServiceClient MobileService = new MobileServiceClient(
  2.      "https://YOUR-SERVICE-HERE.azure-mobile.net/",
  3.      "YOUR-KEY-HERE"
  4.  );

At this point (after replacing the service name and key with the actual values) you should be able to build and run the app.

Just want the app? Go to the MSDN Code Gallery sample.

Comments

  • Anonymous
    November 04, 2014
    I implemented your solution in WPF, it lets me add the first record to the database but then throws a json serialization exception. Did you come across this error while testing? Any idea why its getting thrown?Its occurring in the Refresh items method of the main window.
  • Anonymous
    May 02, 2015
    I had a similar issue, the error was converting the ID into an integer[JsonProperty(PropertyName = "id")]       public string Id { get; set; }changing the id from int to string seemed to fix this, the checkbox works in the example after this
  • Anonymous
    May 26, 2015
    The comment has been removed
  • Anonymous
    June 22, 2015
    The comment has been removed