Windows 8.1 and Visual Studio 2013–Grid Template Explorations

Following up on my previous post I thought I’d poke a little into the Grid project template that ships with Visual Studio 2013 with a good starting point being to do a File->New Project and have a look around.

image

Here’s the “bill of materials” for what’s inside the grid project template as far as Solution Explorer is concerned;

image

I won’t attempt to do a blow-by-blow comparison of this with the Visual Studio 2012 project template although anyone who’s seen that project template will see straight away that this is different because in Visual Studio 2012 there was no SampleData.json data file in the DataModel folder and so this new file perhaps points to Visual Studio 2013 doing something in its template that’s a little more realistic than what was there in VS 2012.

I think it’s fairly clear what the assets are for and in terms of the Common folder here there’s no additional code beyond what was present for the Blank template when you add a “basic page” – it’s the same 5 files that I mentioned in the previous blog post.

In talking to developers who encountered the previous version of this template in Visual Studio 2012, I found that there was always some confusion around it and a lot of that confusion came from the naming of the 3 XAML based views.

If I run the project, then it displays a fairly typical 3-level hierarchy. The first, home, screen is this one below which displays grouped data in a GridView control. This view is called the GroupedItemsPage;

image

and then if I tap on one of the group headers like “Group Title: 1” above I get onto a second page of information for the group and that comes from the GroupDetailPage;

image

and if I tap on a particular item then I get the details for that item and that comes from the ItemDetailPage;

image

and I must admit that I sort of expected a bit more “item detail” on that page than my version of the template is showing me so I wonder if I’ve got some kind of template bug there?

In Visual Studio 2012, this template supported Snapped View (i.e. at 320px) and, as an example, the GroupedItemsPage would use a GridView for display when it wasn’t snapped and a ListView for display when it was snapped.

In the 2013 template the manifest that is being shipped has not set a minimum width for the application;

image

and so the GroupedItemsPage just displays a single view (the GridView) however much I resize the window;

image

In terms of other manifest items – there doesn’t seem to be an awful lot in the template. There’s a fairly minimal set of 4 logos all supplied at 100% scaling rather than at 80%, 140% and 180% and there don’t seem to be any particular capabilities defined in the manifest.

Beyond that, it’s necessary to dig into the code so I figured I’d start with App.xaml and work through the views in the order that most users would encounter them from GroupedItemsPage through to GroupDetailPage and on to ItemDetailPage.

App.xaml

Opening up App.xaml there’s not much in there – in fact it’s distinctly minimal with one string resource called AppName defined to be your app name. Seems easy enough. There’s a bit more going on in the code behind file but it’s not a lot.

The only difference I can see between what the code-behind in this template does and what the blank template does is that this code integrates the SuspensionManager. That is, at the time that the app launches there is code to check if the app was previously terminated by the system and, if it was, then the SuspensionManager is brought into play to attempt to restore any state that had been saved by the app at suspension time. This is via SuspensionManager.RestoreAsync(). 

The template code also overrides the OnSuspending method such that it calls SuspensionManager.SaveAsync() in order to make sure any state that’s being managed by the SuspensionManager is saved at the point where the app gets told to suspend.

That’s about it versus the blank template except, of course, this template then drives navigation to the first page in the app – GroupedItemsPage.

One thing that surprised me a little is that I’d kind of expected to find some code in App.xaml.cs that kick-started an async process to load up some data but it looks like that doesn’t happen here. That said, I did later come across a comment in the data-model code file that said;

// 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. If using this model, you might improve app 
// responsiveness by initiating the data loading task in the code behind for App.xaml when the app 
// is first launched.

GroupedItemsPage.xaml

The GroupedItemsPage is a reasonably simple page and, arguably, slightly simpler than it was in the Visual Studio 2012 version of this template given that the need for a snapped view has gone away and this screen no longer presents any other kind of view. From a first look, I’m not sure that the app does anything to support portrait view as when I rotate this screen it looks like it just gets rotated and (possibly) applies the same margins to the left hand edge of the content in portrait view as it did in landscape view.

Looking at the page, there’s not a lot on there in terms of UI controls. There’s no application bars and the UI is made up of;

image

so it’s essentially a TextBlock (with Text looking up the AppName resource), an AppBarButton (bound to the NavigationHelper.GoBackCommand as I talked about in the previous post) and a GridView. The page takes the same approach to its DataContext as was taken in the basic page item template that I talked about in my previous post – that is, the page sets its DataContext to come from its own DefaultViewModel property;

<Page
    x:Name="pageRoot"
    x:Class="MyGrid.GroupedItemsPage"
    DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"

and into that DefaultViewModel the code-behind drops an instance of an ObservableDictionary.

The AppBarButton (for navigating backwards) is handled in the same way as it was in the basic page item template so the only other thing that’s of note on this page is the GridView which is set up

        <GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Grouped Items"
            Grid.RowSpan="2"
            Padding="116,137,40,46"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            SelectionMode="None"
            IsSwipeEnabled="false"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick">

perhaps the most interesting things there being to flag that the ItemsSource is set to bind to some resource called groupedItemsViewSource. Using F12 to jump to that resource takes me back to the top of this XAML file where it’s defined;

      <!--
            Collection of grouped items displayed by this page, bound to a subset
            of the complete item list because items in groups cannot be virtualized
        -->
        <CollectionViewSource
            x:Name="groupedItemsViewSource"
            Source="{Binding Groups}"
            IsSourceGrouped="true"
            ItemsPath="Items"
            d:Source="{Binding Groups, Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"/>

We’ve got a CollectionViewSource which is binding its Source to Groups but we know that the DataContext here is going to be an ObservableDictionary which is really a form of Dictionary<string,object> and so this CollectionViewSource is going to index into that dictionary with a key of “Groups” and use whatever object it gets back as its ItemsSource. From the ItemsPath property, it’s clear that there’s an expectation that each group object will have an Items property on it via which to get to the collection of items in that group.

What about the d : Source? The d prefix is aliased to Blend’s “http://schemas.microsoft.com/expression/blend/2008"  URI and so this is providing us with design time data but it’s being done differently from the Visual Studio 2012 template.

If you took away the d : Source then, because the designer doesn’t actually run your code then there’d be nothing much visible on the screen in the designer. Like this;

image

so (as in previous versions of Visual Studio and Blend) it’s the sample data that’s doing the work here. These design time extensions aren’t new but I can’t find a complete guide to the latest iterations of them. The best guide I can find seems to be the guide that was written for Silverlight (i.e. this guide) but I think that those docs were written around the idea of sample data being persisted into a XAML file whereas here we’re using a JSON file and I can’t find out exactly how that it used at the time of writing.

My best guess would be that the use of;

image

is saying to the environment to load up SampleData.json and then attempt to deserialize it as an instance of SampleDataSource (followed by of course binding to the Groups property on it). I’m guessing that involves DataContractJsonSerializer but that’s just a guess. It’d be nice to find that confirmed somewhere.

Regardless…we get design time data and that’s what allows Visual Studio to display our grouped collections and the items bound into their respective item templates;

image

In terms of each group there, the project template sets up both a template for each Group header which in this case is just a couple of TextBlocks bound onto the screen;

image

but if you’ll notice – Visual Studio 2013 Preview supports inline editing of these templates. This is very nice indeed and while it’s listed as a feature up on MSDN I can’t find a lot more written about it right now but I think it’s a big improvement over 2012.

I can see that this template is really just providing a data-bound Title for the group and then I can use the same technique to have a look at the ItemTemplate;

image

and, here I can see that I’ve got a couple of data-bound TextBlocks again binding to Title and Subtitle and then also an image (this is an interesting one because that image is actually the grey/dark-grey squares that the item presents so it’s not much of an image!).

That’s pretty much “the UI” – what’s the code behind doing?

In addition to what already happens in the basic page that I talked about in the previous post the code behind this page does 3 things;

  1. In the NavigationHelper.LoadState event handler, it calls SampleDataSource.GetGroupsAsync() and puts the result into the Page’s DefaultViewModel[“Groups”] dictionary so that explains where the data comes from.
  2. When someone clicks on a header element, there’s a handler which grabs the sending object’s DataContext, casts it up to a SampleDataGroup and then uses that object’s UniqueId as a parameter in driving the Frame to navigate to the GroupDetailPage.
  3. When someone clicks on an item element, there’s a handler which grabs the clicked item, casts it up to a SampleDataItem and then passes that item’s UniqueId as a parameter in driving the NavigationHelper to navigate to the ItemDetailPage.

Pretty simple. The data model is;

image

and though the Visual Studio class diagramming tool won’t show it as such – the property SampleDataSource.Groups is a collection of SampleDataGroup and the property SampleDataGroup.Items is a collection of SampleDataItem.

As you might expect, SampleDataSource.GetXXXXAsync() all end up calling SampleDataSource.GetSampleDataAsync() which actually goes and loads the SampleData.json file and parses the contents to produce the groups and items. Once the data is loaded, it’s kept around in the _sampleDataSource static member to avoid loading it multiple times and then the GetGroup/GetGroups/GetItem are all just indexing into data which is memory already.

GroupDetailPage.xaml

The GroupDetailPage is pretty simple. It follows the “basic page” item template scheme by setting up its DataContext to be the DefaultViewModel property and by having a navigation AppBarButton where the Command is bound to the NavigationHelper.GoBackCommand command.

image

and then there’s a GridView which displays the big header for the group (all data-bound);

image

and then there’s the item template;

image

And the data for the GridView comes from binding to a CollectionViewSource in a similar manner to the GroupedItemsPage;

        <GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Items In Group"
            TabIndex="1"
            Grid.RowSpan="2"
            Padding="120,126,120,50"
            ItemsSource="{Binding Source={StaticResource itemsViewSource}}"

which refers to this CollectiveViewSource;

        <CollectionViewSource
            x:Name="itemsViewSource"
            Source="{Binding Items}"
            d:Source="{Binding Groups[0].Items, Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"/>

which, again, binds itself to a property called Items on the DefaultViewModel at run-time and to Groups[0].Items from the sample data at design time ( in this particular project the sample data and the real data are the same anyway ).

In order to make sure that the Header has something sensible to display at design-time, a design-time DataContext is added there with the runtime value being provided by indexing into the DefaultViewModel with a key of “Group”.

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
        DataContext="{Binding Group}"
        d:DataContext="{Binding Groups[0], Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}">

The code behind is pretty much as you’d expect it to be. It’s based on the “basic page” template and adds just a few things. It loads up the right bits of data and assigns them into the right indexed slot in the DefaultViewModel;

        private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
            // TODO: Create an appropriate data model for your problem domain to replace the sample data
            var group = await SampleDataSource.GetGroupAsync((String)e.NavigationParameter);
            this.DefaultViewModel["Group"] = group;
            this.DefaultViewModel["Items"] = group.Items;
        }

and then there is just a click handler such that when someone clicks on an item in the GridView the handler executes, casts up the passed clicked object to an instance of ItemDetailPage and then uses the Frame to navigate across to the ItemDetailPage passing that object as a parameter.

ItemDetailPage.xaml

The last page in the picture follows pretty much the same route as the other pages in that it’s similar to the “basic page” item template. There’s not a whole lot going on with this page in that the only content on the page is a data-bound Title which shows up at the top;

image

and then there’s a Grid which sets up its DataContext to pull the value of a key “Item” from the DefaultViewModel;

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
        DataContext="{Binding Item}"
        d:DataContext="{Binding Groups[0].Items[0], Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}">

and the code behind sets this up using the navigation parameter;

        private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
        {
            // TODO: Create an appropriate data model for your problem domain to replace the sample data
            var item = await SampleDataSource.GetItemAsync((String)e.NavigationParameter);
            this.DefaultViewModel["Item"] = item;
        }

Wrapping Up

That’s pretty much it – that’s the grid template. There’s a bit of complexity in there in terms of some of the data-bindings leading into dictionaries of data but it’s all fairly simple. What I’d hope to do is revisit it and perhaps re-implement it using something like PRISM to see how that would look as an alternative way of doing this. I’ll see if I can get that done…