March 2014

Volume 29 Number 3

Modern Apps : A Look at the Hub Project and Control in Windows Store Apps

Rachel Appel | March 2014

Rachel AppelWhen it comes to development on Windows with Visual Studio, the built-in project templates are a good place to start. If you’re new to Windows Store (or any Microsoft stack) development, the templates can serve as a learning tool. In this article, I’ll look at the Hub control, but in context of the Hub project template. I’ll examine all the important things to know about the Hub project and control for both HTML and XAML apps.

The Hub project in particular enables you to deliver a large volume of content to the user while using a modern UX. This is because you can break the app’s content into parts called HubSections, so the app doesn’t overwhelm the user visually with large amounts of data. While this is just my opinion, I find the Hub project to be the most aesthetically interesting of all the Windows Store app templates. The content layout is in distinct sections that are easy to digest. You can parade a favorite piece of content in the front-and-center “hero” section of the hub, while the remaining content items are easily accessible in groups.

Of course, it’s not mandatory that you use the templates—you can start from a blank project. However, for many developers, it’s far easier to customize and expand upon the templates, as the code is set up for you.

The Hub Project Template

Visual Studio 2013 contains Hub project templates for both HTML and XAML. Upon creating a new HTML project using the template, you’ll see some familiar project folders such as the css, images and js folders. In addition to the customary folders are the Hub-specific folders: pages\hub, pages\item and pages\section. As you might expect, each of these folders contains files that correspond to their purpose in the app. In the project root is the file for the package manifest as well as default.html, the app’s starting point, which loads default.js and performs functions related to the app and lifecycle management. Default.html contains references to not just the \js\default.js file but also \js\data.js, which contains sample data, and \js\navigator.js, which performs navigation. For a refresher on navigation, see my August 2013 column, “Navigation Essentials in Windows Store Apps,” at msdn.microsoft.com/magazine/dn342878. In short, the Hub project template, like other templates, is a quick way to publish visually interesting modern apps.

Of course, the centerpiece of the Hub project is the Hub control. While default.html is the project starting point in an app built with the Windows Library for JavaScript (WinJS), once it loads, it immediately navigates to the hub.html file. Hub.html contains the Hub control and lives in the \pages\hub directory. The Hub control is what you use to create a modern layout that’s more than just boring groups of squares. Instead, the Hub control, coupled with asynchronous data fetching, enables you to present large amounts of data—or data that has distinct groups—in an organized yet fashionable manner.

The Hub template implements the hub, or hierarchical, navigational pattern. This means that from the starting point (that is, hub page), the user can navigate to a page containing all the members of a particular section, or the user can navigate to an individual item from the hub page. The template also contains navigation to an item page from a section page. While the template contains navigation code only between section 3 and its groups and items (see Figure 1), you can use the ListView or Repeater controls to do the same type of navigation for other sections if it makes sense for your app. Figure 1 illustrates what the default Hub app with sample data looks like at run time.

The Hub Control at Run Time for Both HTML and XAML Apps
The Hub Control at Run Time for Both HTML and XAML Apps
The Hub Control at Run Time for Both HTML and XAML Apps
Figure 1 The Hub Control at Run Time for Both HTML and XAML Apps

With the reimagining of Windows came the notion of putting content front and center, and, as you can see, this template does just that.

The XAML Hub template project works the same conceptually as does the HTML template, relying on the hub as the main entry point, being navigable to sections and details. Of course, the implementation is different, and you can see this by examining the folder structure, which reveals the following directories: Assets, Common, DataModel and Strings. These folders contain what you might expect: assets such as graphics, data in the DataModel folder and localized strings in the Strings folder. In the root of the project lies the following working files needed so the app can run:

  • App.xaml/.cs: This is the XAML equivalent of default.html. It has a tiny bit of code that assists in navigation and general tasks.
  • HubPage.xaml/.cs: This is the crowning jewel of the app, containing the Hub control.
  • ItemPage.xaml/.cs: This contains the individual items you can navigate to from the hub or section pages.
  • SectionPage.xaml/.cs: This shows all individual data members that belong to a particular group.
  • Package.appmanifest: This contains the app settings.

The XAML Hub project template’s HubPage.xaml file reveals the Hub control firmly seats itself in a Grid control that serves as the root container for the page and Hub.

In the DataModel folder is a file named SampleData.json containing sample data. Also in the folder is a SampleDataSource.cs file that transforms the JSON data into usable classes for C# or Visual Basic .NET consumption and XAML data binding. You can replace this with your own data, much like the data.js file in WinJS apps.

The Common folder contains several files that perform a variety of tasks such as navigation and other generally app-related tasks for working with data in view models. In addition, the Common folder contains the SuspensionManager.cs file, which performs process lifecycle tasks. Finally, the Strings folder contains localized strings for publishing in different locales.

The Hub Control

Both HTML and XAML project templates use the Hub control. In HTML apps, the Hub control works just like any other WinJS control. Use the data-win-control attribute of an HTML element, usually a <div>, to define it as a Hub control, as this code shows:

<div class="hub" data-win-control="WinJS.UI.Hub"></div>

This means the WinJS.UI.Hub object is the brains behind the Hub control. The Hub control acts as a container for the HubSection controls, which define sections or groups of data. HubSections can contain any valid HTML tags, such as <div> or <img>, or a WinJS control, such as the ListView control. By default, the hub.html file’s Hub control encloses five sections, one named hero and four more designated by their class attributes (such as section1, section2 and so on). In the HubSections, the <div> and <img> tags are the most common child elements, but any valid HTML or WinJS controls will work to display data in a different layout. Changing the layout is a great way to personalize your app, but don’t forget to adhere to the Windows UX guidelines at bit.ly/1gBDHaW. Figure 2 shows a complete sample of the necessary HTML (you’ll see its CSS later) to create a Hub control with five sections. Inspecting the code in Figure 2 shows section 3 is the navigable section, while the rest are not navigable.

Figure 2 The HTML that Creates the Hub Control

<div class="hub" data-win-control="WinJS.UI.Hub">
  <div class="hero" data-win-control="WinJS.UI.HubSection"></div>
  <div class="section1" data-win-control="WinJS.UI.HubSection"
     data-win-options="{ isHeaderStatic: true }"
     data-win-res="{ winControl: {'header': 'Section1'} }">
    <img src="/images/gray.png" width="420" height="280" />
    <div class="subtext win-type-x-large" data-win-res="
      { textContent: 'Section1Subtext' }"></div>
    <div class="win-type-medium"
       data-win-res="{ textContent: 'DescriptionText' }"></div>
    <div class="win-type-small">
      <span data-win-res="{ textContent: 'Section1Description' }"></span>
      <span data-win-res="{ textContent: 'Section1Description' }"></span>
      <span data-win-res="{ textContent: 'Section1Description' }"></span>
    </div>
  </div>
  <div class="section2" data-win-control="WinJS.UI.HubSection" data-win-options="{
 isHeaderStatic: true }" data-win-res="{ winControl: {'header': 'Section2'} }">
  <div class="item-title win-type-medium" data-win-res="{ textContent: 'Section2ItemTitle' }"></div>
    <div class="article-header win-type-x-large" data-win-res="{ textContent: 'Section2Subtext' }"></div>
    <div class="win-type-xx-small" data-win-res="{ textContent: 'Section2ItemSubTitle' }"></div>
    <div class="win-type-small">
      <span data-win-res="{ textContent: 'Section2Description' }"></span>
      <span data-win-res="{ textContent: 'Section2Description' }"></span>
      <span data-win-res="{ textContent: 'Section2Description' }"></span>
      <span data-win-res="{ textContent: 'Section2Description' }"></span>
      <span data-win-res="{ textContent: 'Section2Description' }"></span>
      <span data-win-res="{ textContent: 'Section2Description' }"></span>
    </div>
  </div>
  <div class="section3" data-win-control="WinJS.UI.HubSection" data-win-res="{
 winControl: {'header': 'Section3'} } "data-win-options="{
    onheaderinvoked: select('.pagecontrol').winControl.section3HeaderNavigate }">
    <div class="itemTemplate" data-win-control="WinJS.Binding.Template">
      <img src="#" data-win-bind="src: backgroundImage; alt: title" />
      <div class="win-type-medium" data-win-bind="textContent: title"></div>
      <div class="win-type-small" data-win-bind="textContent: description"></div>
      </div>
      <div class="itemslist win-selectionstylefilled" data-win-control="WinJS.UI.ListView"
        data-win-options="{layout: {type: WinJS.UI.GridLayout},
        selectionMode: 'none', itemTemplate: select('.section3 .itemTemplate'),
        itemDataSource:select('.pagecontrol').winControl.section3DataSource,
         oniteminvoked: select('.pagecontrol').winControl.section3ItemNavigate }">
      </div>
    </div>
  <div class="section4" data-win-control="WinJS.UI.HubSection" data-win-options="{
   isHeaderStatic: true }" data-win-res="{ winControl: {'header': 'Section4'} }">
    <div class="top-image-row">
      <img src="/images/gray.png" />
    </div>
    <div class="sub-image-row">
      <img src="/images/gray.png" />
      <img src="/images/gray.png" />
      <img src="/images/gray.png" />
    </div>
    <div class="win-type-medium"       data-win-res="{ textContent: 'DescriptionText' }"></div>
    <div class="win-type-small">
      <span data-win-res="{ textContent: 'Section4Description' }"></span>
      <span data-win-res="{ textContent: 'Section4Description' }"></span>
    </div>
  </div>
</div>

In XAML, the Hub control uses a <Hub> element that contains <Hub.Header> and <HubSection> elements. In turn, the child headings and sections contain Grid and other XAML controls, such as the StackPanel, as well as text blocks. Figure 3 shows the XAML required to create the Hub control used in the Visual Studio templates.

Figure 3 The XAML for a Hub Control

<Hub SectionHeaderClick="Hub_SectionHeaderClick">
  <Hub.Header>
    <!-- Back button and page title -->
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="80"/>
        <ColumnDefinition Width="*"/>
      </Grid.ColumnDefinitions>
      <Button  x:Name="backButton" Style="{StaticResource NavigationBackButtonNormalStyle}"
        Margin="-1,-1,39,0"
        VerticalAlignment="Top"
        Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
        AutomationProperties.Name="Back"
        AutomationProperties.AutomationId="BackButton"
        AutomationProperties.ItemType="Navigation Button"/>
      <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}"
        Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1"
        VerticalAlignment="Top" IsHitTestVisible="false" TextWrapping="NoWrap" />
    </Grid>
  </Hub.Header>
  <HubSection Width="780" Margin="0,0,80,0">
    <HubSection.Background>
      <ImageBrush ImageSource="Assets/MediumGray.png" Stretch="UniformToFill" />
    </HubSection.Background>
  </HubSection>
  <HubSection Width="500" x:Uid="Section1Header" Header="Section 1">
    <DataTemplate>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition Height="*" />
          </Grid.RowDefinitions>
          <Image Source="Assets/MediumGray.png" Stretch="Fill" Width="420" Height="280"/>
          <TextBlock Style="{StaticResource SubheaderTextBlockStyle}"
            Grid.Row="1" Margin="0,10,0,0" TextWrapping="Wrap"
            x:Uid="Section1Subtitle" Text="Lorem ipsum dolor sit nonumy sed consectetuer ising elit, sed diam"/>
          <TextBlock Style="{StaticResource TitleTextBlockStyle}"
            Grid.Row="2" Margin="0,10,0,0" x:Uid="DescriptionHeader" Text="Description text:"/>
          <TextBlock Style="{StaticResource BodyTextBlockStyle}" Grid.Row="3"
            x:Uid="Section1DescriptionText" Text="Lorem ipsum dolor sit amet... "/>
      </Grid>
    </DataTemplate>
  </HubSection>
  <HubSection Width="520" x:Uid="Section2Header" Header="Section 2">
    <DataTemplate>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock Style="{StaticResource TitleTextBlockStyle}"
           Margin="0,0,0,10" x:Uid="ItemTitle" Text="Item Title" />
        <TextBlock Style="{StaticResource SubheaderTextBlockStyle}"
           Grid.Row="1" x:Uid="Section2UnderTitle" Text="Quisque in porta
           lorem dolor amet sed consectetuer ising elit, sed diam non
           my nibh uis mod wisi quip."/>
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}"
           Grid.Row="2" Margin="0,20,0,0" x:Uid="ItemSubTitle"
           Text="Item Sub Title"/>
        <TextBlock Style="{StaticResource BodyTextBlockStyle}" Grid.Row="3"
          x:Uid="LongText" Text="Lorem ipsum dolor sit amet..."/>
      </Grid>
    </DataTemplate>
  </HubSection>
  <HubSection IsHeaderInteractive="True"
     DataContext="{Binding Section3Items}" d:DataContext="{Binding Groups[3],
     Source={d:DesignData Source=/DataModel/SampleData.json,
     Type=data:SampleDataSource}}" x:Uid="Section3Header" Header="Section 3"
     Padding="40,40,40,32">
    <DataTemplate>
      <GridView
        x:Name="itemGridView"
        ItemsSource="{Binding Items}"
        Margin="-9,-14,0,0"
        AutomationProperties.AutomationId="ItemGridView"
        AutomationProperties.Name="Items In Group"
        ItemTemplate="{StaticResource Standard310x260ItemTemplate}"
        SelectionMode="None"
        IsSwipeEnabled="false"
        IsItemClickEnabled="True"
        ItemClick="ItemView_ItemClick">
      </GridView>
    </DataTemplate>
  </HubSection>
  <HubSection x:Uid="Section4Header" Header="Section 4">
    <DataTemplate>
      <!-- width of 400 -->
      <StackPanel Orientation="Vertical">
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="130"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="130"/>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="130"/>
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="270"/>
            <RowDefinition Height="95"/>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
          </Grid.RowDefinitions>
          <Image Source="Assets/MediumGray.png"
             Grid.ColumnSpan="5" Margin="0,0,0,10" Stretch="Fill" />
          <Image Source="Assets/MediumGray.png" Grid.Row="1" Stretch="Fill"/>
           <Image Source="Assets/MediumGray.png" Grid.Row="1"
              Grid.Column="2" Stretch="Fill"/>
          <Image Source="Assets/MediumGray.png" Grid.Row="1"
              Grid.Column="4" Stretch="Fill"/>
          <TextBlock Style="{StaticResource TitleTextBlockStyle}"
             Grid.Row="2" Grid.ColumnSpan="5"  Margin="0,15,0,0"
            x:Uid="DescriptionHeader" Text="Description text:"/>
          <TextBlock Style="{StaticResource BodyTextBlockStyle}"
             Grid.Row="3" Grid.ColumnSpan="5" x:Uid="LongText"
             Text="Lorem ipsum dolor sit amet...."/>
        </Grid>
      </StackPanel>
    </DataTemplate>
  </HubSection>
</Hub>

As you can see, XAML syntax is a bit more verbose than HTML. That’s because you code layout and styles right in the XAML page (though XAML styles can be placed in a resource dictionary), while in HTML the layout and style rules are CSS (more on styling later).

Data Binding and the Hub Control

Arrays or JSON (which usually serializes to an array anyway) are the customary ways to work with data in WinJS, as well as in many other Web or client languages. This is no different with the Hub project. You can replace the data in \js\data.js with custom data broken into however many groups you plan to use. You’ll find two arrays as sample data in the data.js file, one for grouping and one for individual items that tie into a specific group. If you’re familiar with some of the other WinJS project templates, then you’ll notice this is the same sample data.

In the \pages\hub\hub.js file are the calls to the members of the Data namespace that obtain group and item data:

var section3Group = Data.resolveGroupReference("group4");
var section3Items = Data.getItemsFromGroup(section3Group);

The section3Group and section3Items are global objects. Figure 2 shows the data-binding syntax for the ListView control. In hub.js, after the ready function, the code sets section3DataSource, a property of the Hub control:

section3DataSource: section3Items.dataSource,

The Hub control uses the preceding code to data bind to the ListView (Figure 2 shows the data-bound ListView code).

In XAML apps using C#, you have the same basic occurrences, as code from the HubPage.xaml.cs file indicates the following declaration for a view model of type ObservableDictionary, along with its corresponding property declaration (this is where you can return your own data):

private ObservableDictionary defaultViewModel = new ObservableDictionary();
public ObservableDictionary DefaultViewModel
{
  get { return this.defaultViewModel; }
}

Later in the file, code sets a page-level view model by calling GetGroupAsync, which, as its name implies, runs asynchronously: 

var sampleDataGroup = await SampleDataSource.GetGroupAsync("Group-4");

Although the call obtains Group-4 data, you assign it to a view model named Section3Items to assign it to those items. Consider the hero section as Section 0, meaning the Section 3 items will align with the Group-4 data:

this.DefaultViewModel["Section3Items"] = sampleDataGroup;

This is all you need in the codebehind. In XAML, notice the DataContext attribute binds to Section3Items.The other attributes aren’t necessary for data binding, but act as an aid for the design tools in Visual Studio or Blend, as designated by the “d” namespace:

<HubSection IsHeaderInteractive="True" DataContext="{Binding Section3Items}" 
  d:DataContext="{Binding Groups[3], Source={d:DesignData
  Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"
  x:Uid="Section3Header" Header="Section 3" Padding="40,40,40,32">

While working with local sample data, you have many options for data access, including File IO, SQLite, Web Storage, IndexedDB, REST services and Windows Azure, to name a few. If you want to review what data options are available, see my March 2013 article, “Data Access and Storage Options in Windows Store Apps,” at msdn.microsoft.com/magazine/jj991982.

Styling the Hub Control

In Windows Store apps built with JavaScript, you can style the Hub control with CSS. The \hub\hub.css file contains all the default CSS related to the Hub control. Feel free to add your own styles to change the size of the elements or their layout. Figure 4 shows the complete CSS in hub.css. Notice there’s a .hubpage class selector that uses HTML5 semantic role attributes such as header[role=banner] and section[role=main] to designate the general styles for the hub. After that, the CSS in Figure 4 shows the “.hubpage .hub .hero” descendant selector, which creates the featured (hero) section of the Hub control. The hero fills roughly half of the left side of the viewable part of screen with a light gray background and, of course, it’s a great way to put a special piece of content where no user can miss it! You can fill it with lots of data, and graphic data or multimedia works quite nicely to show off here.

Figure 4 The CSS That Shapes and Styles the HTML Hub Control

.hubpage header[role=banner] {
  position: relative;
  z-index: 2;
}
.hubpage section[role=main] {
  -ms-grid-row: 1;
  -ms-grid-row-span: 2;
  z-index: 1;
}
.hubpage .hub .win-hub-surface {
  height: 100%;
}
.hubpage .hub .hero {
  -ms-high-contrast-adjust: none;
  background-image: url(/images/gray.png);
  background-size: cover;
  margin-left: -80px;
  margin-right: 80px;
  padding: 0;
  width: 780px;
}
  .hubpage .hub .hero:-ms-lang(
    ar, dv, fa, he, ku-Arab, pa-Arab, prs, ps, sd-Arab,
     syr, ug, ur, qps-plocm) {
    margin-left: 80px;
    margin-right: -80px;
  }
  .hubpage .hub .hero .win-hub-section-header {
    display: none;
  }
  .hubpage .hub .section1 {
    width: 420px;
  }
  .hubpage .hub .section1 .win-hub-section-content {
    overflow-y: hidden;
  }
  .hubpage .hub .section1 .subtext {
    margin-bottom: 7px;
    margin-top: 9px;
  }
.hubpage .hub .section2 {
  width: 440px;
}
  .hubpage .hub .section2 .win-hub-section-content {
    overflow-y: hidden;
  }
  .hubpage .hub .section2 .item-title {
      margin-top: 4px;
      margin-bottom: 10px;
  }
  .hubpage .hub .section2 .article-header {
    margin-bottom: 15px;
  }
.hubpage .hub .section3 {
}
  .hubpage .hub .section3 .itemslist {
    height: 100%;
    margin-left: -10px;
    margin-right: -10px;
    margin-top: -5px;
  }
  .hubpage .hub .section3 .win-container {
    margin-bottom: 36px;
    margin-left: 10px;
    margin-right: 10px;
  }
  .hubpage .hub .section3 .win-item {
      height: 229px;
      width: 310px;
  }
      .hubpage .hub .section3 .win-item img {
        height: 150px;
        margin-bottom: 10px;
        width: 310px;
      }
.hubpage .hub .section4 {
  width: 400px;
}
  .hubpage .hub .section4 .win-hub-section-content {
        overflow-y: hidden;
  }
  .hubpage .hub .section4 .top-image-row {
    height: 260px;
    margin-bottom: 10px;
    width: 400px;
  }
    .hubpage .hub .section4 .top-image-row img {
      height: 100%;
       width: 100%;
    }
.hubpage .hub .section4 .sub-image-row {
  margin-bottom: 20px;
  display: -ms-flexbox;
  -ms-flex-flow: row nowrap;
  -ms-flex-pack: justify;
}
  .hubpage .hub .section4 .sub-image-row img {
    height: 95px;
     width: 130px;
  }

As you can see, the CSS in Figure 4 shapes and styles the Hub control, and most of it deals with the layout and sizing of the HubSections. Elements and WinJS controls inside the HubSections apply the styles from ui-light.css or ui-dark.css, until you overwrite them with your own styles.

HTML apps rely on CSS for styling. XAML apps rely on XAML for styling. This means that XAML has several attributes you apply to tags to enforce styling definitions called resources. For example, the code that styles a TextBlock is the Style attribute and it references a built-in (static resource dictionary) style named SubheaderTextBlockStyle:

<TextBlock Style="{StaticResource SubheaderTextBlockStyle} />

The layout of a page is also XAML, as all the Hubs, Grids and other elements contain inline coordinates for their on-screen position as well as size. You can see throughout Figure 3 there are margins, positioning, and row and column settings that position elements, all inline in the XAML. HTML is originally a Web technology, and conserving bandwidth by using CSS instead of HTML is a real benefit. Here in the land of XAML, it’s all client-side, so UI caching isn’t so much of an issue and styles can go inline. A nice upside of XAML is that you need to do very little to ensure a responsive design. Just be sure to set two <RowDefinition> elements to a height of “Auto” and “*”:

<Grid.RowDefinitions>
  <RowDefinition Height="Auto"/>
  <RowDefinition Height="*"/>
</Grid.RowDefinitions>

The rows will automatically respond to app view state changes, making the layout fluid while saving extra code. Figure 3 shows a few references to auto-height row definitions. 

Samples Available

Once you’ve modified the Hub control, performed data retrieval and binding, and set styles, you’re good to go. Don’t forget to add modern touches such as tiles, search and other Windows integration to your app. The Hub project template is an easy way to build and publish apps quickly, whether in HTML or XAML. Using the hub navigational pattern with the Hub control enables you to build an effective and rich UX that adheres to modern UI principles. You can download Hub control samples covering many aspects of Windows app development at the following locations:


Rachel Appel is a consultant, author, mentor and former Microsoft employee with more than 20 years of experience in the IT industry. She speaks at top industry conferences such as Visual Studio Live!, DevConnections, MIX and more. Her expertise lies within developing solutions that align business and technology focusing on the Microsoft dev stack and open Web. For more about Appel, visit her Web site at rachelappel.com.

Thanks to the following technical expert for reviewing this article: Frank La Vigne (Microsoft)