Binding the Interface in Windows Store apps

Download

Right click “Save as…”

 

In the previous Quickstarts, we have introduced the app and looked at handling data requests and formatting. In this next video, we will look at binding that data to the interface.

Binding and Windows 8 Templates

Data binding plays a central role in the Windows Store project templates available in Visual Studio 2012. For our project, we used the Grid App template available in Visual Studio 2012 as our base for the Khan Academy app. So let's see how this template is setup.

As we discussed in the first Quickstart of this series, creating a new project based on the Grid template will populate your project with sample pages and assets, a common folder of useful classes, and a data folder with a view model all ready to go. The default XAML pages such as GroupedItemsPage.xaml will also be wired up as they will inherit from LayoutAwarePage.cs in the Common folder to common system events of initialization, navigation and orientation.

But also notice the inclusion of a new class called BindableBase.cs in the Common folder. The default Data Model comes with every Template project inherits its collection elements from this class and by studying how the sample pages are wired up to the default Data Model is a great way to get up to speed quickly on Data Binding basics in Windows 8.

clip_image001

Let’s take a closer look at the Data Model for a Grid App Template project, DataModel\SampleDataSource.cs. This class has a collection of Groups in an ObservableCollection called AllGroups. Each group in AllGroups contains an ObservableCollection of DataItems. Both the SampleDataGroup and SampleDataItem inherit from the SampleDataCommon class.

The SampleDataCommon class, in turn, inherits from Common\BindableBase.cs, which we introduced above, and which allows all the objects to be bound by the UI controls.

SampleDataSource.cs

public abstract class SampleDataCommon : AppName.Common.BindableBase

In this Grid App Template, when the app first starts and App.xaml loads the landing page called GroupedItemsPage.xaml, the following code is run:

GroupedItemsPage.xaml.cs:

protected override void LoadState(
    Object navigationParameter,
    Dictionary<String, Object> pageState)
{
    var sampleDataGroups = SampleDataSource.GetGroups(
        (String)navigationParameter);
    this.DefaultViewModel["Groups"] = sampleDataGroups;
}

In this template sample, we create our Data Model by calling the SampleDataSource’s GetGroups() function, which returns an IEnumerable of SampleDataGroup values. This bindable collection of Groups is then assigned to the DefaultViewModel's Group element.

But what is a DefaultViewModel[“Groups”] element anyway? Remember, these UI Pages we are exploring in the Template project all inherit from Common\LayoutAwarePage.cs:

GroupedItemsPage.xaml.cs

public sealed partial class GroupedItemsPage
    : AppName.Common.LayoutAwarePage
{
    public GroupedItemsPage()
    {
        this.InitializeComponent();
    }
    […]

And here we see the true power of leveraging the Windows Store Project Templates as a basis for projects. LayoutAwarePage.cs is a robust implementation of a Windows 8 app page that provides several important conveniences: app view state to visual state mapping, page navigation event handlers and mouse and keyboard shortcuts, state management for navigation and process lifetime management, and most relevant to us right now, a default view model too:

C#

public LayoutAwarePage()
{
    if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
        return;
 
    // Create an empty default view model
    this.DefaultViewModel =
        new ObservableDictionary<String, Object>();   
    […]

The last piece of the puzzle for binding is found in the resources of the page:

GroupedItemsPage.xaml

<Page.Resources>
    <CollectionViewSource
        x:Name="groupedItemsViewSource"
        Source="{Binding Groups}"
        IsSourceGrouped="true"
        ItemsPath="TopItems"
        d:Source="{Binding AllGroups,
            Source={d:DesignInstance
            Type=data:SampleDataSource,
            IsDesignTimeCreatable=True}}"/>
</Page.Resources>

Here, a CollectionViewSource is being bound to the Groups element of the DefaultViewModel, which we just set to the response of SampleDataSource.GetGroups(). A CollectionViewSource allows you to sort, filter and group the underlying data without directly manipulating the data.

Finally, the control on the page that will display the information has its ItemsSource property bound to the groupedItemsViewSource, which is a CollectionViewSource.

XAML 

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

Since there are no custom styles yet, the Item Template pulls from some standard templates also found in the Common folder to make everything work. If the CollectionViewSource has properly grouped data and the IsSourceGrouped property is set to true, the GridView takes care of the rest.

 

The Khan Academy View Model

In the Khan Academy app, we follow a very similar pattern with a couple of changes.

First, as we’ve seen in the previous two Quickstarts, we are instantiating our KhanDataSource View Model from App.xaml directly in it’s LaunchApp() handler and then passing it along when we navigate to our landing page of choice.

App.xaml.cs

public async void LaunchApp(
     ApplicationExecutionState previousExecutedState)
{
     DataSource = new KhanDataSource();
     await DataSource.LoadAllData();
     var rootFrame = new Frame();
[…]
     if ( rootFrame.Content == null)
     {
          if ( !rootFrame.Navigate(
               typeof(HubPage),
               JsonSerializer.Serialize(DataSource.TopicGroups)))
          {
               throw new Exception(“Failed to create initial page”);
          }
     }
     Window.Current.Content = rootFrame;
     Window.Current.Activate();
}

When HubPage.xaml.cs, receives our Data Model upon initialization in its LoadState() handler, it uses this Data Model for its own local binding as shown below:

HubPage.xaml.cs 

protected override void LoadState(
     Object navigationParameter,
     Dictionary<String, Object> pageState)
{
     ObservableCollection<TopicItem> items =
          JsonSerializer.Deserialize<ObservableCollection<TopicItem>>(
               navigationParameter as string);
     this.DefaultViewModel[“Groups”] = items;
     this.groupGridView.ItemsSource = items;
}

Another difference between the KhanDataSource and the default SampleDataSource that comes with Template projects is an additional tier of data. Instead of having a simple collection of groups that contain items, the data returned from Khan Academy is organized by the app into top level Topics ( such as Math, Science, Hummanities, etc.), which each contain a collection of playlists ( Algebra, Arithmetic, Calculus, etc..). Each of these playlists is made up of a series of VideoItems that play the actual lessons.

To add an additional layer of complexity, to achieve a Hub experience in our welcoming page, we wanted to display multiple types of content to give the user a richer selection of items. However, having multiple types of content on the same container creates both a visual and navigational challenge.

For example, most of the groups displayed in HubPage.xaml are made up of playlist objects that have a title and description but no associated graphic.

 image

Selecting a playlist object should take you to the ItemDetail.xaml page.

But we also wanted to feature at a top level videos from two specific playlists, New & Noteworthy and Talks & Interviews. These videoItems do have a associated thumbnail of the video they represent and clicking on these elements should take you to the VideoPage.xaml instead of the ItemDetail.xaml page.

 image

We will discuss how we visually differentiate the styling of these two different types of objects in the next Quickstart. But for now, let us look at how we handle the Items being selected:

C#

void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
    if ( e.ClickItem.GetType() == typeof(PlaylistItem))
    {
        this.Frame.Navigate(
            typeof(ItemDetailPage),
           JsonSerializer.Serialize(e.ClickedItem));
    }
    else if ( e.ClickedItem.GetType() == typeof(VideoItem))
    {
        this.Frame.Navigate(
            typeof(VideoPage),
            JsonSerializer.Serialize(e.ClickedItem));
    }
}

Since we are sharing a data binding between two different types of content, we query the type of the item and pass the clicked item to the appropriate page.

If the user selected a video, we would go to the video player page which uses the video player from the Microsoft.Metro.PlayerFramework referenced in the Project. Selecting a playlist, though, takes you to the ItemDetailPage.xaml to show you the list of videos in that list. The data binding on the ItemDetailPage.xaml page works the same way once it receives the serialized ClickedItem as a navigationParameter in its LoadState() method.

C#

protected override void LoadState(
    Object navigationParameter,
    Dictionary<String, Object> pageState)
{
    PlaylistItem playlist =
        JsonSerializer.Deserialize<PlaylistItem>(
            navigationParameter as string);
    this.DefaultViewModel[“Group”] = playlist;
    this.DefaultViewModel[“Items”] = playlist.Videos;
}

The other pages in the Khan Academy app follow the same pattern. An item is selected, the app's Frame then Navigates to the appropriate Page, passing the selected item as a parameter, and finally the loaded Page parses the passed in object, and populates its local View Model with the appropriate data.

Now that our components are displaying the appropriate data and navigating to the correct Pages, it's time to add visual identity. In the next Quickstart, we will look at custom styling.

If you have any questions, comments, or feedback feel free to join in the discussion.

Twitter: @rickbarraza, @joelmartinez

Tags:

Follow the Discussion

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.