How to provide cloud-based, JSON data to Windows 8 Metro Grid Applications – Part 2
Exercise 1: Understanding how a Windows 8 Metro Grid Application Works
Download the Windows Azure SDK and Tools - To do these posts, absolutely necessary |
How to provide cloud-based, JSON data to Windows 8 Metro Grid Applications - Part 1 | https://blogs.msdn.com/b/brunoterkaly/archive/2012/06/12/how-to-provide-cloud-based-json-data-to-windows-8-metro-grid-applications.aspx |
How to provide cloud-based, JSON data to Windows 8 Metro Grid Applications - Part 2 | https://blogs.msdn.com/b/brunoterkaly/archive/2012/06/14/how-to-provide-cloud-based-json-data-to-windows-8-metro-grid-applications-part-2.aspx |
How to provide cloud-based, JSON data to Windows 8 Metro Grid Applications - Part 3 | https://blogs.msdn.com/b/brunoterkaly/archive/2012/06/15/how-to-provide-cloud-based-json-data-to-windows-8-metro-grid-applications-part-3.aspx |
How to provide cloud-based, JSON data to Windows 8 Metro Grid Applications - Part 4 | https://blogs.msdn.com/b/brunoterkaly/archive/2012/06/17/how-to-provide-cloud-based-json-data-to-windows-8-metro-grid-applications-part-3-windows-azure-cloud.aspx |
Source Code |
This post will focus on the data model used by this type of application. We need to understand how data is modeled if we plan to architect a cloud-based back-end.
The next few screens will talk a lot about SampleDataGroup and SampleDataItem objects. These are the core data objects used by a Windows 8 Metro Grid Application.
Exercise 1: Task 1 - Creating the starter application with File/New with Visual Studio 2012 RC
The following steps illustrate what is needed to create the starter application.
- Start Visual Studio 2012 RC.
- Select File, New Project
- Choose “Grid App (XAML) ”
- Provide a name.
- Warning if you are using your own namespace, be sure when you copy my code you make the appropriate changes.
- Your namespaces will be off
- Warning if you are using your own namespace, be sure when you copy my code you make the appropriate changes.
- I recommend sticking with FastMotorcycle
This is the running version of a File/New Metro Grid Application.
Take note of the “groups” and the “items”
- Notice there are 3 groups (more if you scroll to the right)
- Group: Title 1
- This group has many items
- Group: Title 2
- This group has many items
- Group: Title 3
- This group has many items
- Group: Title 1
Exercise 1: Task 2 - Understanding the files generated (Solution Explorer)
There are 2 core things to notice: (1) SampleDataSource.cs – is where we learn about the needed data model. (2) The 3 XAML files (described below) provide the needed user interface.
- The core files in a Windows 8 Metro Grid Style Application
- These files where generated by Visual Studio 2012
- NOTE: You won’t see motorcycles on your version
- That is the version we will build in the next post or 2.
- We will need to add that branding later
- NOTE: You won’t see motorcycles on your version
- These files where generated by Visual Studio 2012
- What is important to notice is the 3 files:
- GroupDetailPage.xaml
- Gives details about a group. In this case, the group can be “Sport Bikes” or “Exotic Bikes”
- GroupedItemsPage.xaml
- Shows Groups and Items.
- This is the initial page seen by users
- You can navigate to the group or to an individual item from here
- ItemDetailPage.xaml
- Provides details about and individual item. In this case, it is about an individual motorcycle.
- GroupDetailPage.xaml
Exercise 1: Task 3 - The core files in a Windows 8 Metro Grid Style Application
The object model needed to support a Windows 8 Metro Grid application is visible below. Common sense dictates that when we create the server-side software, we will need to somehow model this object model on both ends (client and server).
- The things to notice is: (1) there are 3 classes total, one is a base class (2) there is a one to many relationship
- There are 3 classes:
- SampleDataCommon
- SampleDataItem
- SampleDataGroup
- One SampleDataGroup contains many SampleDataItem objects. Most of the lists of “things” in this object model is expressed as a ObservableCollection<T>. This data structure provides a convenient eventing model (currently being ignored) so that we can notice edits or changes in the related data objects.
- See the collection _items
- A SampleDataItem has 2 things
- Content to display for an individual SampleDataItem
- A group (SampleDataGroup).
- Each individual SampleDataItem points to its parent.
- There is a base class
- It is SampleDataCommon. It inherits from BindableBase. This provides support as follows:
- public abstract class BindableBase : INotifyPropertyChanged
- It provides support for Multicast events, resulting from property change notifications
- It is SampleDataCommon. It inherits from BindableBase. This provides support as follows:
- There are two derived classes from SampleDataCommon:
- SampleDataItem
- SampleDataGroup
- There are important relationships here:
- A group has many items
- An item always belongs to some group
To summarize, the core files in a Windows 8 Metro Grid Style Application
- This object model is used by the user interface.
- GroupDetailPage.xaml
- Shows a group with a list of items
- GroupedItemsPage.xaml
- Shows both groups and items
- ItemDetailPage.xaml
- Shows an individual item
- GroupDetailPage.xaml
- The code below is provided by the framework to simplify working with INotifyPropertyChanged. BindableBase is something we just use and don’t worry about.
CLASS = BindableBase
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | public abstract class BindableBase : INotifyPropertyChanged
{
/// <SUMMARY>
/// Multicast event for property change notifications.
/// </SUMMARY>
public event PropertyChangedEventHandler PropertyChanged;
/// <SUMMARY>
/// Checks if a property already matches a desired value. Sets the property and
/// notifies listeners only when necessary.
/// </SUMMARY>
/// <TYPEPARAM name="T">Type of the property.</TYPEPARAM>
/// <PARAM name="storage">Reference to a property with both getter and setter.</PARAM>
/// <PARAM name="value">Desired value for the property.</PARAM>
/// <PARAM name="propertyName">Name of the property used to notify listeners. This
/// value is optional and can be provided automatically when invoked from compilers that
/// support CallerMemberName.</PARAM>
/// <RETURNS>True if the value was changed, false if the existing value matched the
/// desired value.</RETURNS>
protected bool SetProperty<T>( ref T storage, T value, [CallerMemberName] String propertyName = null )
{
if ( object .Equals(storage, value)) return false ;
storage = value;
this .OnPropertyChanged(propertyName);
return true ;
}
/// <SUMMARY>
/// Notifies listeners that a property value has changed.
/// </SUMMARY>
/// <PARAM name="propertyName">Name of the property used to notify listeners. This
/// value is optional and can be provided automatically when invoked from compilers
/// that support <SEE cref="CallerMemberNameAttribute" />.</PARAM>
protected void OnPropertyChanged([CallerMemberName] string propertyName = null )
{
var eventHandler = this .PropertyChanged;
if (eventHandler != null )
{
eventHandler( this , new PropertyChangedEventArgs(propertyName));
}
}
} |
Exercise 2: SampleDataCommon, SampleDataItem, SampleDataGroup – the core
This is what we’ll need to really understand inside of SampleDataSource.cs.
- The base class is SampleDataCommon
- It gives us the basic strings in a picture of a motorcycle or group (Sport Bikes, Exotic Bikes)
- Note that SampleDataItem has 2 extra fields
- _content
- A string that displays the text details of a specific motorcycle
- _group
- A SampleDataGroup object, which represents the group to which a SampleDataItem belongs
- _content
- SampleDataGroup
- Contains an array of SampleDataItem objects ( _items collection)
Exercise 2: Task 1 - Understanding the relationships
A group has many items and an item has exactly one group
- The core files in a Windows 8 Metro Grid Style Application
- A group has many items
- SampleDataGroup has an “_items” collection
- An item has “content” and a “group”
- Note that a SampleDataItem points back to the group to which it belongs
Exercise 2: Task 2 - Everything goes into _allGroups
You only add SampleDataGroups. SampleDataItem are already part of SampleDataGroups.
- The _allGroups collection is where everything ends up.
- The SampleDataGroup should already have its collection of SampleDataItem Objects
- Each SampleDataItem will point to its parent (SampleDataGroup)
- All this data originates as JSON data, obtained from a Windows Azure (Cloud-based) back-end.
- This is the code that populates _allGroups.
- The code below is the constructor for SampleDataSource. It hard codes all the data.
- Eventually we will replace all this code with http calls to get JSON data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | public SampleDataSource()
{
String ITEM_CONTENT = String.Format( "Item Content: {0}\n\n{0}\n\n{0}\n\n{0}\n\n{0}\n\n{0}\n\n{0}" ,
"Curabitur class ..." );
var group1 = new SampleDataGroup( "Group-1" ,
"Group Title: 1" ,
"Group Subtitle: 1" ,
"Assets/DarkGray.png" ,
"Group Description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus tempor scelerisque lorem in vehicula. Aliquam tincidunt, lacus ut sagittis tristique, turpis massa volutpat augue, eu rutrum ligula ante a ante" );
group1.Items.Add( new SampleDataItem( "Group-1-Item-1" ,
"Item Title: 1" ,
"Item Subtitle: 1" ,
"Assets/LightGray.png" ,
"Item Description: Pellentesque porta, mauris quis interdum vehicula, urna sapien ultrices velit, nec venenatis dui odio in augue. Cras posuere, enim a cursus convallis, neque turpis malesuada erat, ut adipiscing neque tortor ac erat." ,
ITEM_CONTENT,
group1));
this .AllGroups.Add(group1);
// Repeat for all groups. here is for Group 2
var group2 = new SampleDataGroup( "Group-2" ,
"Group Title: 2" ,
"Group Subtitle: 2" ,
"Assets/LightGray.png" ,
"Group Description: Lorem " );
group2.Items.Add( new SampleDataItem( "Group-2-Item-1" ,
"Item Title: 1" ,
"Item Subtitle: 1" ,
"Assets/DarkGray.png" ,
"Item Description: Pellentesque porta, " ,
ITEM_CONTENT,
group2));
this .AllGroups.Add(group2);
// Omitted for brevity
} |
Exercise 2: Task 3 - The sample project derived from the Grid Template that Visual Studio 2012 RC creates contains hard coded data
The class is called SampleDataSource.
- The constructor adds all the SampleDataGroups and SampleDataItems we discussed previously.
Exercise 3: Understanding how the constructor maps to the user interface.
This is key if we plan to supply our own JSON data instead. The class SampleDataSource has a constructor that adds test data.
- You can start to see how the code in the constructor for SampleDataSource maps to specific visible elements in the running application
- Our job will be re-factor this code (generated by Visual Studio 2012 when File/New Metro Grid application is chosen)
- We will instead make a call into Azure Cloud-based RESTful services to retrieve data for the Windows 8 Metro Grid Application.
Let's look at some of the built in classes.
We will take a look SampleDataCommon, SampleDataGroup, SampleDataItem.
CLASS = SampleDataCommon
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | [Windows.Foundation.Metadata.WebHostHidden]
public abstract class SampleDataCommon : FastMotorcycle.Common.BindableBase
{
private static Uri _baseUri = new Uri( "ms-appx:///" );
public SampleDataCommon(String uniqueId, String title, String subtitle, String imagePath, String description)
{
this ._uniqueId = uniqueId;
this ._title = title;
this ._subtitle = subtitle;
this ._description = description;
this ._imagePath = imagePath;
}
private string _uniqueId = string .Empty;
public string UniqueId
{
get { return this ._uniqueId; }
set { this .SetProperty( ref this ._uniqueId, value); }
}
private string _title = string .Empty;
public string Title
{
get { return this ._title; }
set { this .SetProperty( ref this ._title, value); }
}
private string _subtitle = string .Empty;
public string Subtitle
{
get { return this ._subtitle; }
set { this .SetProperty( ref this ._subtitle, value); }
}
private string _description = string .Empty;
public string Description
{
get { return this ._description; }
set { this .SetProperty( ref this ._description, value); }
}
private ImageSource _image = null ;
private String _imagePath = null ;
public ImageSource Image
{
get
{
if ( this ._image == null && this ._imagePath != null )
{
this ._image = new BitmapImage( new Uri(SampleDataCommon._baseUri, this ._imagePath));
}
return this ._image;
}
set
{
this ._imagePath = null ;
this .SetProperty( ref this ._image, value);
}
}
public void SetImage(String path)
{
this ._image = null ;
this ._imagePath = path;
this .OnPropertyChanged( "Image" );
}
} |
CLASS = SampleDataGroup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class SampleDataGroup : SampleDataCommon
{
public SampleDataGroup(String uniqueId, String title, String subtitle, String imagePath, String description)
: base (uniqueId, title, subtitle, imagePath, description)
{
}
private ObservableCollection<SAMPLEDATAITEM> _items = new ObservableCollection<SAMPLEDATAITEM>();
public ObservableCollection<SAMPLEDATAITEM> Items
{
get { return this ._items; }
}
public IEnumerable<SAMPLEDATAITEM> 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
get { return this ._items.Take(12); }
}
} |
CLASS = SampleDataItem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class SampleDataItem : SampleDataCommon
{
public SampleDataItem(String uniqueId, String title, String subtitle, String imagePath, String description, String content, SampleDataGroup group)
: base (uniqueId, title, subtitle, imagePath, description)
{
this ._content = content;
this ._group = group;
}
private string _content = string .Empty;
public string Content
{
get { return this ._content; }
set { this .SetProperty( ref this ._content, value); }
}
private SampleDataGroup _group;
public SampleDataGroup Group
{
get { return this ._group; }
set { this .SetProperty( ref this ._group, value); }
}
} |
Conclusion: Re-factoring our Windows 8 Metro Grid Application
We will need to call into a RESTful cloud-based, Azure back-end. We will need to eliminate the SampleDataSource.cs and add our own version. We will base our version on the existing version and simply modify it so it is a FastMotorcycle Application, not the basic test project. FastMotorcycle Application will be a Windows 8 Metro Grid Application that makes RESTful calls to get data. To understand the next steps, you need to understand the data structure and layout.
- The Windows 8 Metro Grid Application provides amazing built in power. You simply need to provide it a basic parent-child data relationship, and the built in Grid Template Application can manage quite a bit.
- You do not need to build much of a user interface as the default one provided works very well.
- Groups will naturally display a list of items.
- Items will belong group and the user interface will allow you to seamlessly go back and forth between groups and items.
- This blog has covered some basics:
- How to create a new Metro project in Visual Studio
- How to work with the structure of the project and the files included
- How to work with the existing data model in terms of groups and items
- The next blog will:
- Replace SampleDataSource.cs with a new version that makes asynchronous calls to retrieve cloud-hosted JSON data
- Brand the application by supplying custom imagery for tiles and other elements
- Consume that JSON data in our application and data-bind it to a ListView control
Download for Azure SDK |