Download the Windows Azure SDK and Tools - To do these posts, absolutely necessary
This post is broken down into 3 exercises.
public
MySampleDataGroup(JsonObject currGroup)
{
//
// Extract attributes from the JsonObject
IJsonValue val;
if
(currGroup.TryGetValue(
"_uniqueId"
,
out
val))
this
.UniqueId = val.GetString();
"_title"
.Title = val.GetString();
"_subTitle"
.Subtitle = val.GetString();
"_imagePath"
.SetImage(val.GetString());
"_description"
.Description = val.GetString();
"_content"
.Content = val.GetString();
using
System;
System.Linq;
System.Collections.Generic;
System.Collections.ObjectModel;
System.ComponentModel;
System.Runtime.CompilerServices;
Windows.ApplicationModel.Resources.Core;
Windows.Foundation;
Windows.Foundation.Collections;
Windows.UI.Xaml.Data;
Windows.UI.Xaml.Media;
Windows.UI.Xaml.Media.Imaging;
System.Net.Http;
Windows.Data.Json;
System.Threading.Tasks;
// The data model defined by this file serves as a representative example of a strongly-typed
// model that supports notification when members are added, removed, or modified. The property
// names chosen coincide with data bindings in the standard item templates.
// Applications may use this model as a starting point and build on it, or discard it entirely and
// replace it with something appropriate to their needs.
namespace
FastMotorcycle
/// <SUMMARY>
///
/// This is the base class to MySampleDataGroup and MySampleDataGroup
/// It provides some common data structures and some eventing mechanisms
/// </SUMMARY>
[Windows.Foundation.Metadata.WebHostHidden]
abstract
class
MySampleDataCommon : FastMotorcycle.Common.BindableBase
private
static
Uri _baseUri =
new
Uri(
"ms-appx:///"
);
MySampleDataCommon()
}
// Constructor for the core elements of the base class.
MySampleDataCommon(String uniqueId,
string
title,
subTitle,
imagePath,
description,
content)
._uniqueId = uniqueId;
._title = title;
._subTitle = subTitle;
._description = description;
._content = content;
.SetImage(imagePath);
_uniqueId =
.Empty;
UniqueId
get
return
._uniqueId; }
set
.SetProperty(
ref
._uniqueId, value); }
_title =
Title
._title; }
._title, value); }
_subTitle =
Subtitle
._subTitle; }
._subTitle, value); }
_description =
Description
._description; }
._description, value); }
_content =
Content
._content; }
._content, value); }
ImageSource _image =
null
;
_imagePath =
ImagePath
_imagePath; }
{ _imagePath = value; }
ImageSource Image
(
._image ==
&&
._imagePath !=
)
._image =
BitmapImage(
Uri(MySampleDataCommon._baseUri,
._imagePath));
._image;
._imagePath =
._image, value);
// This method makes sure the image is viewable as an ImageSource
void
SetImage(String path)
._imagePath = path;
.OnPropertyChanged(
"Image"
/// This is the core MySampleDataItem. It will hold information about motorcycles and the
/// group to which they belong
MySampleDataItem : MySampleDataCommon
MySampleDataItem()
MySampleDataItem(String uniqueId,
content, MySampleDataGroup group)
:
base
(uniqueId, title, subTitle, description, imagePath, content)
._group = group;
// The main constructor for an item. The code here searches for attributes
// in JSON objects. It then populate relevant properties.
// In this implementation, it will really hold "Fast Motorcycles"
MySampleDataItem(JsonObject currItem, MySampleDataGroup currGroup)
uniqueId =
.Empty, title =
.Empty, subTitle =
.Empty,
description =
.Empty, imagePath =
.Empty, content =
(currItem.TryGetValue(
uniqueId = val.GetString();
title = val.GetString();
subTitle = val.GetString();
imagePath = val.GetString();
description = val.GetString();
content = val.GetString();
// Inherited members
.UniqueId = uniqueId;
.Title = title;
.Subtitle = subTitle;
.Description = description;
.Content = content;
// Additional data member (items point to their parent)
.Group = currGroup;
MySampleDataGroup _group;
MySampleDataGroup Group
._group; }
._group, value); }
/// This is the fundamental type for groups. It will be either Sport Bikes or Exotic Bikes. It will hold a
/// collection of individual MySampleDataItem objects.
MySampleDataGroup : MySampleDataCommon
MySampleDataGroup()
MySampleDataGroup(String uniqueId,
(uniqueId, title, subTitle, imagePath, description, content)
// MySampleDataGroup has a collection of MySampleDataItem
ObservableCollection<MYSAMPLEDATAITEM> _items =
ObservableCollection<MYSAMPLEDATAITEM>();
ObservableCollection<MYSAMPLEDATAITEM> Items
._items; }
IEnumerable<MYSAMPLEDATAITEM> TopItems
// Provides a subset of the full items collection to bind to from a GroupedItemsPage
// for two reasons: GridView will not virtualize large items collections, and it
// improves the user experience when browsing through groups with large numbers of
// items.
// A maximum of 12 items are displayed because it results in filled grid columns
// whether there are 1, 2, 3, 4, or 6 rows displayed
._items.Take(12); }
/// This is the main container class for MySampleDataItem and MySampleDataGroup objects
/// Creates a collection of groups and items with data from a an JSON/http web request.
sealed
MySampleDataSource
MySampleDataSource _sampleDataSource =
MySampleDataSource();
MyStack mystack =
MyStack();
// This is the main entry point for all objects into the system.
// Essentially, we add MySampleDataGroup objects to _allGroups. Each
// MySampleDataGroup object will have a collection of MySampleDataItem objects.
ObservableCollection<MYSAMPLEDATAGROUP> _allGroups =
ObservableCollection<MYSAMPLEDATAGROUP>();
ObservableCollection<MYSAMPLEDATAGROUP> AllGroups
._allGroups; }
IEnumerable<MYSAMPLEDATAGROUP> GetGroups(
uniqueId)
(!uniqueId.Equals(
"AllGroups"
))
throw
ArgumentException(
"Only 'AllGroups' is supported as a collection of groups"
_sampleDataSource.AllGroups;
MySampleDataGroup GetGroup(
// Simple linear search is acceptable for small data sets
var matches = _sampleDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
(matches.Count() == 1)
matches.First();
MySampleDataItem GetItem(
var matches = _sampleDataSource.AllGroups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
// This is the main method that retrieves JSON data by making an asynchronous web requet.
// Currently, it is calling a local emulator instance of Windows Azure.
// Note the web address of "http://127.0.0.1/FastMotorcycleListService...."
async Task<JSONARRAY> LoadRemoteDataAsync()
// Retrieve fastmotorcycle data from Azure
var client =
HttpClient();
client.MaxResponseContentBufferSize = 1024 * 1024;
// Read up to 1 MB of data
var response = await client.GetAsync(
"http://127.0.0.1:81/FastMotorcycleListService.svc/list/SampleData/1"
));
var result = await response.Content.ReadAsStringAsync();
// Parse the JSON fastmotorcycle data
var fastmotorcycles = JsonArray.Parse(result);
// Convert the JSON objects into MySampleDataItems and MySampleDataGroups
// Assume that we are ordered by Group, then by Item
JsonArray array = fastmotorcycles;
IJsonValue groupKey;
foreach
(var item
in
array)
var obj = item.GetObject();
(!obj.TryGetValue(
"_group"
groupKey))
continue
// must have _group, skip if not
else
// This code tracks "groups"
// If a group already exists, and we have a new item to add, then add item to group
// If we do find a new group, add it to our stack. The stack object is used
// to add new items to a group.
var currGroup = groupKey.GetObject();
MySampleDataGroup newGroup =
MySampleDataGroup(currGroup);
(!mystack.Exists(newGroup))
mystack.Add(newGroup);
// Add item to latest group
// Make sure child points to its own group.
// Children items point to parent (group)
MySampleDataItem newItem =
MySampleDataItem(obj, mystack.GetLatestGroup());
mystack.AddChildToLatestGroup(newItem);
// Loop through all groups and a group to _sampleDataSource.AllGroups
// This is one of the main entry points for data into the user interface.
MySampleDataGroup loadedGroup =
for
int
i = 0; i < mystack.stackCount; i++)
loadedGroup = mystack.GetEntry(i);
// Retrieve group from bottom of stack
_sampleDataSource.AllGroups.Add(loadedGroup);
array;
MySampleDataSource()
// Empty. Data retrieved from JSON call.
System.Text;
MyStack
stackCount;
MySampleDataGroup[] stack;
MyStack()
stackCount = 0;
stack =
MySampleDataGroup[1000];
internal
Add(MySampleDataGroup myNode)
stack[stackCount++] = myNode;
bool
IsChild(
i)
false
// stack[i].Depth > stack[i - 1].Depth;
IsEqual(
k)
// stack[k].Depth == stack[k - 1].Depth;
IsLast(
k == stackCount;
Exists(MySampleDataGroup newGroup)
(stackCount == 0)
stack[stackCount - 1].UniqueId == newGroup.UniqueId;
AddChildToLatestGroup(MySampleDataItem newItem)
newItem.Group = stack[stackCount - 1];
stack[stackCount - 1].Items.Add(newItem);
MySampleDataGroup GetEntry(
stack[i];
MySampleDataGroup GetLatestGroup()
stack[stackCount - 1];
FastMotorcycle.Common;
System.IO;
Windows.ApplicationModel;
Windows.ApplicationModel.Activation;
Windows.UI.Xaml;
Windows.UI.Xaml.Controls;
Windows.UI.Xaml.Controls.Primitives;
Windows.UI.Xaml.Input;
Windows.UI.Xaml.Navigation;
// The Grid App template is documented at http://go.microsoft.com/fwlink/?LinkId=234226
/// Provides application-specific behavior to supplement the default Application class.
partial
App : Application
MySampleDataSource sampleData =
/// Initializes the singleton Application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
App()
.InitializeComponent();
.Suspending += OnSuspending;
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// <PARAM name="args">Details about the launch request and process.</PARAM>
protected
override
async
OnLaunched(LaunchActivatedEventArgs args)
// Do not repeat app initialization when already running, just ensure that
// the window is active
(args.PreviousExecutionState == ApplicationExecutionState.Running)
Window.Current.Activate();
await MySampleDataSource.LoadRemoteDataAsync();
// Create a Frame to act as the navigation context and associate it with
// a SuspensionManager key
var rootFrame =
Frame();
SuspensionManager.RegisterFrame(rootFrame,
"AppFrame"
(args.PreviousExecutionState == ApplicationExecutionState.Terminated)
// Restore the saved session state only when appropriate
await SuspensionManager.RestoreAsync();
(rootFrame.Content ==
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
(!rootFrame.Navigate(
typeof
(GroupedItemsPage),
Exception(
"Failed to create initial page"
// Place the frame in the current Window and ensure that it is active
Window.Current.Content = rootFrame;
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// <PARAM name="sender">The source of the suspend request.</PARAM>
/// <PARAM name="e">Details about the suspend request.</PARAM>
OnSuspending(
object
sender, SuspendingEventArgs e)
var deferral = e.SuspendingOperation.GetDeferral();
await SuspensionManager.SaveAsync();
deferral.Complete();
// The Group Detail Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234229
/// A page that displays an overview of a single group, including a preview of the items
/// within the group.
GroupDetailPage : FastMotorcycle.Common.LayoutAwarePage
GroupDetailPage()
/// Populates the page with content passed during navigation. Any saved state is also
/// provided when recreating a page from a prior session.
/// <PARAM name="navigationParameter">The parameter value passed to
/// <SEE cref="Frame.Navigate(Type, Object)" /> when this page wtas initially requested.
/// </PARAM>
/// <PARAM name="pageState">A dictionary of state preserved by this page during an earlier
/// session. This will be null the first time a page is visited.</PARAM>
LoadState(Object navigationParameter, Dictionary<STRING, Object> pageState)
// TODO: Create an appropriate data model for your problem domain to replace the sample data
var group = MySampleDataSource.GetGroup((String)navigationParameter);
.DefaultViewModel[
"Group"
] = group;
"Items"
] = group.Items;
/// Invoked when an item is clicked.
/// <PARAM name="sender">The GridView (or ListView when the application is snapped)
/// displaying the item clicked.</PARAM>
/// <PARAM name="e">Event data that describes the item clicked.</PARAM>
ItemView_ItemClick(
sender, ItemClickEventArgs e)
// Navigate to the appropriate destination page, configuring the new page
// by passing required information as a navigation parameter
var itemId = ((MySampleDataItem)e.ClickedItem).UniqueId;
.Frame.Navigate(
(ItemDetailPage), itemId);
// The Grouped Items Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234231
/// A page that displays a grouped collection of items.
GroupedItemsPage : FastMotorcycle.Common.LayoutAwarePage
GroupedItemsPage()
/// <SEE cref="Frame.Navigate(Type, Object)" /> when this page was initially requested.
var sampleDataGroups = MySampleDataSource.GetGroups((String)navigationParameter);
"Groups"
] = sampleDataGroups;
/// Invoked when a group header is clicked.
/// <PARAM name="sender">The Button used as a group header for the selected group.</PARAM>
/// <PARAM name="e">Event data that describes how the click was initiated.</PARAM>
Header_Click(
sender, RoutedEventArgs e)
// Determine what group the Button instance represents
var group = (sender
as
FrameworkElement).DataContext;
(GroupDetailPage), ((MySampleDataGroup)group).UniqueId);
/// Invoked when an item within a group is clicked.
<COMMON:LAYOUTAWAREPAGE mc:Ignorable=
"d"
xmlns:mc=
"http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d=
"http://schemas.microsoft.com/expression/blend/2008"
xmlns:common=
"using:FastMotorcycle.Common"
xmlns:data=
"using:FastMotorcycle"
xmlns:local=
xmlns:x=
"http://schemas.microsoft.com/winfx/2006/xaml"
xmlns=
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
IsTabStop=
"false"
DataContext=
"{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
x:Class=
"FastMotorcycle.ItemDetailPage"
x:Name=
"pageRoot"
>
<?XML:NAMESPACE PREFIX =
"[default] http://schemas.microsoft.com/winfx/2006/xaml/presentation"
NS =
/><Page.Resources>
<!-- Collection of items displayed by
page -->
<CollectionViewSource x:Name=
"itemsViewSource"
d:Source=
"{Binding AllGroups[0].Items, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"
Source=
"{Binding Items}"
></CollectionViewSource>
</Page.Resources>
<!--
This grid acts
a root panel
the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid DataContext=
"{Binding Group}"
d:DataContext=
"{Binding AllGroups[0], Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"
<Grid.RowDefinitions>
<RowDefinition Height=
"140"
></RowDefinition>
"*"
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=
"Auto"
></ColumnDefinition>
</Grid.ColumnDefinitions>
<BUTTON x:Name=
"backButton"
IsEnabled=
"{Binding Frame.CanGoBack, ElementName=pageRoot}"
Click=
"GoBack"
<TextBlock Text=
"{Binding Title}"
"pageTitle"
Grid.Column=
"1"
></TextBlock>
</Grid>
The remainder of the page
is
one large FlipView that displays details
one item at a time, allowing the user to flip through all items
the chosen
group
<FlipView tabIndex=1 Margin=
"0,-3,0,0"
"flipView"
ItemsSource=
"{Binding Source={StaticResource itemsViewSource}}"
Grid.Row=
AutomationProperties.Name=
"Item Details"
AutomationProperties.AutomationId=
"ItemsFlipView"
<FlipView.ItemTemplate>
<DataTemplate>
UserControl chosen
the templated item because it supports visual state management
Loaded/unloaded events explicitly subscribe to view state updates from the page
<UserControl Unloaded=
"StopLayoutUpdates"
Loaded=
"StartLayoutUpdates"
<ScrollViewer x:Name=
"scrollViewer"
<!-- Content
allowed to flow across
many columns
needed -->
<COMMON:RICHTEXTCOLUMNS Margin=
"117,0,117,47"
"richTextColumns"
<RichTextBlock x:Name=
"richTextBlock"
Width=
"560"
<Paragraph>
<Run Text=
FontWeight=
"Light"
FontSize=
"26.667"
></Run>
<LineBreak></LineBreak>
"{Binding Subtitle}"
"SemiBold"
</Paragraph>
<Paragraph LineStackingStrategy=
"MaxHeight"
<InlineUIContainer>
<IMG Margin=
"0,20,0,10"
"image"
"{Binding Image}"
Stretch=
"Uniform"
MaxHeight=
"480"
</InlineUIContainer>
"{Binding Description}"
"SemiLight"
"{Binding Content}"
</RichTextBlock>
<!-- Additional columns are created from
template -->
<COMMON:RICHTEXTCOLUMNS.COLUMNTEMPLATE>
<RichTextBlockOverflow Margin=
"80,0,0,0"
<RichTextBlockOverflow.RenderTransform>
<TranslateTransform Y=
"4"
X=
"-1"
></TranslateTransform>
</RichTextBlockOverflow.RenderTransform>
</RichTextBlockOverflow>
</DataTemplate>
</COMMON:RICHTEXTCOLUMNS.COLUMNTEMPLATE>
</COMMON:RICHTEXTCOLUMNS>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state inside the FlipView -->
<VisualStateGroup x:Name=
"ApplicationViewStates"
<VisualState x:Name=
"FullScreenLandscape"
></VisualState>
"Filled"
<!-- Respect the narrower 100-pixel margin convention
portrait -->
"FullScreenPortrait"
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=
"Margin"
Storyboard.TargetName=
<DiscreteObjectKeyFrame Value=
"97,0,87,57"
KeyTime=
"0"
></DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
"400"
</Storyboard>
</VisualState>
<!-- When snapped, the content
reformatted and scrolls vertically -->
"Snapped"
"17,0,17,57"
"Style"
"{StaticResource VerticalScrollViewerStyle}"
"Width"
"280"
"160"
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ScrollViewer>
</UserControl>
</FlipView.ItemTemplate>
</FlipView>
<!-- Visual states reflect the application's view state -->
<!-- The back button respects the narrower 100-pixel margin convention
"{StaticResource PortraitBackButtonStyle}"
<!-- The back button and title have different styles when snapped -->
"{StaticResource SnappedBackButtonStyle}"
"{StaticResource SnappedPageHeaderTextStyle}"
</COMMON:LAYOUTAWAREPAGE>
<PRE></PRE><P></P><DIV></DIV><P></P><DIV></DIV>
<DIV></DIV>
</BUTTON>
FastMotorcycle.Data;
// The Item Detail Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234232
/// A page that displays details for a single item within a group while allowing gestures to
/// flip through other items belonging to the same group.
ItemDetailPage : FastMotorcycle.Common.LayoutAwarePage
ItemDetailPage()
// Allow saved page state to override the initial item to display
(pageState !=
&& pageState.ContainsKey(
"SelectedItem"
navigationParameter = pageState[
];
var item = MySampleDataSource.GetItem((String)navigationParameter);
] = item.Group;
] = item.Group.Items;
.flipView.SelectedItem = item;
/// Preserves state associated with this page in case the application is suspended or the
/// page is discarded from the navigation cache. Values must conform to the serialization
/// requirements of <SEE cref="SuspensionManager.SessionState" />.
/// <PARAM name="pageState">An empty dictionary to be populated with serializable state.</PARAM>
SaveState(Dictionary<STRING, Object> pageState)
var selectedItem = (MySampleDataItem)
.flipView.SelectedItem;
pageState[
] = selectedItem.UniqueId;
Hi
This is a great article, do you have an example how do connect Fast MotorCycle to Azure Services?
[Thanks...Please provide a more detailed question...Bruno]
hi, I am trying to connect the VS Store App template to Azure mobile services, I have also looked closely as the Contoso Cookbook demo. There are plenty of simple examples connecting a simple page to Azure Mobile Services, but I cannot find and struggled to connect the Grid Template or similar? Any help would be much appropriated...
[see this post
http://blogs.msdn.com/b/brunoterkaly/archive/2013/01/07/parsing-json-by-hand-from-azure-mobile-services.aspx
....Bruno]
hi and thank you for parsing json by hand example.
In regards to your Fast Motorcycle example above, can you give provide an example what the table / Field schema would look like in Azure Mobile Services?
[At the bottom of this post, I give you some guidance, Andrew.]