MDI / Multiple Tabs Flat Navigation App Bar in Windows Store Apps

Summary

The Windows 8 User Experience Guidelines mentions two different navigation designs: the hierarchical and the flat system. As said in the guidelines, most Windows Store apps use the hierarchical system. But I needed a flat navigation. And in addition, I needed a way to implement a Multiple Document Interface (MDI) like approach. Or, in other words, an IE 10 like multiple tabs flat system interface.

IE 10 Tab Navigation

This sample implements such an app bar. The user can add new tabs (pages), switch between open pages, and of course remove existing. The app bar holds a navigation list of all currently open pages.

The user can enable / disable some app bar animation when a new page is added. The side effects of this, and a reason why one might prefer the animation, are explained in detail below.

Another configuration setting is available to set the way the navigation list reacts on user interaction. One option is to open an existing tab by just tapping on it (single tap). To select an item from the navigation list, the user has to right tap it. The app gives visual feedback when right tapping is registered. (Right tapping means to press and hold until a time threshold is crossed.)

The other option is to select the navigation item by a single tap and open the page by double tapping. Because tap events a fired by finger tapping, mouse click or pen input, the app does not have to distinguish between different input devices.

Below you will find descriptions and explanations of some of the implementation details.

You Cannot Capture a Screenshot

My initial idea was to capture a screenshot of the current page and display the list of screenshots in the app bar. This is what the IE 10 app is doing.

But I had to learn that this is not possible in XAML Windows Store apps (see How to capture screen in Metro app?? in Dev Center).

Even using DirectX will not solve the problem. I tried the .NET / RT DirectX implementation SharpDX. It lacks of one key feature: create a copy of the output to be able to acquire the next frame. But from what I understand, this is not a SharpDX issue.

For those who ask why IE can: it is using its own rendering engine.

This is why there is no thumbnail thing in the navigation list, but a simple rectangle containing text. Of course, one might put some time in symbol design. But that is not the focus of this sample.

Global App Bar Definition

The navigation app bar might be defined for every page class that is used by the app. In this sample, the app bar is declared globally. The reason is that no matter which page is opened, the app bar always looks the same. Having different kinds of content pages, there might be the need to define different kinds of app bar.

The global AppBar is defined in the MainPage XAML. The main page itself has no content (beside some informational text that is hidden when a content page is added). It contains a Frame that hosts the current content page. Instead of navigating to the newly created page, the frame’s content is set to this page. So the MainPage is always present, and this is why its app bar will be shown.

I found the initial sample for this in Create Global AppBar in Windows Store Apps Using XAML/C#.

App Bar Animation

Animating new tabs means that the app bar stays open for a while when the add button is pressed. An indeterminate progress bar gets started. The new page opens, the new tab is added to the app bar’s list (animated), and then the app bar closes.

Having no animation, the app bar closes immediately when the add button is pressed, while the new page opens.

A drawback of having no animation, from my point of view, is when you open the app bar for the first time after a new tab was added. Without animation, all tabs are newly rendered with transition. On my machine, this took a while. I was not able to find out how to disable the transition. So the user waits a while until all tabs are visible. Opening the app bar again, without adding new tabs, the items are visible immediately.

Having the animation, the app looks like some background activities are required to setup the new page. The time the app bar stays open is not deterministic. So you might have to change to delay when using it in your own app. But when the app bar is re-opened, all items are displayed immediately.

All the content page adding code, together with the app bar animation, can be found in MainPage.OnAddButtonClicked.

Animation Update (V1.1.0.0)

Checking the sample on a Windows 8.1 Preview system, I noticed that the navigation tabs were shown with transition every time the app bar was opened – no matter if animation was enabled or not.

So I started again looking for the right place to disable transition of GridViewItems in the app bar. And I found it 🙂 In C# you have to set

GridView.ItemContainerTransitions = null;

or define in XAML

 <GridView>
  <GridView.ItemContainerTransitions/>
</GridView>

To be able to animate new items in the list, the sample stores the ItemContainerTransitions in MainPage.NavigationItemTransitionCollection when all UI controls were initialized. The collection is restored only in MainPage.OnAddButtonClicked when animation is requested and a new content page gets added.

Update 2013-10-25
In case you cannot see any animation under Windows 8.1, please check the Performance Options setting “Animate controls and elements inside windows” (System / Advanced system settings / Performance / Settings). If this option is not set, transition is disabled for Windows Store apps too.

User Interaction Considerations

My first approach for user interaction with the tab navigation was like this: single click opens the selected page. Right click selects the item for removal. Why just clicking? Because my dev machine has no touch display, and I almost do not run the apps in the simulator.

After having this coded, I switched to the simulator, testing the navigation in basic tap mode. Have you ever tried to right tap? The Quickstart: Static gestures says “A single contact that does not move until a time threshold is crossed. […] Right tap is closely associated with the press and hold gesture. The right tap event is fired when the press and hold is released.”. This is true so far. I received right tap events.

But there is no (visual) feedback by default for GridView when the time threshold is crossed. So when will the user knows she has right tapped? And the app won’t know either. This is because the RightTapped event is fired when the press and hold is released, not when the time threshold is crossed. Accordingly, the app cannot give visual feedback itself.

So I re-designed the navigation. Single click / single tap selects an item. Double click / double tap opens it.

Then I found this thread: Right tapped visual feedback rectangle. OK, the visual feedback is not built in, but can be added with a few event handler. So I implemented both versions. Still can’t tell which one I like more.

Failed to start tracking the pointer because it is already being tracked

Handling the CoreWindow.PointerPressed, CoreWindow.PointerReleased, and CoreWindow.PointerMoved for right-tapped visual feedback, I sometimes had an unhandled exception saying “Failed to start tracking the pointer because it is already being tracked”.

Well, the thread Failed to start tracking the pointer because it is already being tracked gave the important information, and I found it also in the remarks of the docs of UiElement.PointerCaptureLost event (unfortunately not in the remarks of CoreWindow.PointerPressed): “PointerCaptureLost might fire instead of PointerReleased. Don’t rely on PointerPressed and PointerReleased events always occurring in pairs. To function properly, your app must listen for and handle all events that represent likely conclusions to the Press action, and that includes PointerCaptureLost. A pointer can lose capture either because of user interactions or because you programmatically captured another pointer or released the current pointer capture deliberately.

Adding a PointerCaptureLost handler helped on this.

private void OnCoreWindowPointerCaptureLost
  (
  object sender,
  PointerEventArgs args
  )
{
  // Just set the flag that we've lost the capture.
  PointerCaptureIsLost = true;
}

The flag needs to be tested by the PointerPressed handler.

private void OnCoreWindowPointerPressed
  (
  object sender,
  PointerEventArgs args
  )
{
  // In case we've lost the pointer capture, just reset the flag and do nothing.
  // Otherwise, an exception will be thrown that says 
  // "Failed to start tracking the pointer, because it is already being tracked".
  if (PointerCaptureIsLost)
  {
    PointerCaptureIsLost = false;
    return;
  }

  // We still have the capture, so handle the event.
  GestureRecognizer.ProcessDownEvent(args.CurrentPoint);
}

Which Source of Pointer Events?

I was playing around to figure out from which source the pointer events should be handled. At least I think it is best to take Window.Current.CoreWindow. All pointer event handling is implemented in MainPage.

One approach was to only handle these events from the GridView that contains the navigation list. This lead to some unwanted behavior. When I right-tapped the app bar, waited until the visual feedback was shown, then moved the pointer without releasing it, the highlighted rectangle stayed open. Even when I switched to another app, the start screen, or close the app: the rectangle was not closed any more. At least this is how the app behaved in the simulator.

Tapping Empty GridView in AppBar Causes Unhandled Exception

Some unexpected things happen when I tapped into the empty GridViewGridView, and then into the main window (so that the app bar closes). When I repeat these steps for a second time (starting with opening the app bar), after tapping into the main window, the app terminates. As soon as the GridView contains at least one item, the error does not occur.

At the time of writing, I have not received a response / explanation for this. So maybe you want to make sure there is at minimum one item left in the list, means one content page needs to be open.

Get the Sources Directly

Click here to download the source code.

Load It From The Windows Store

A slightly extented version of the sample can be found in the Windows Store.

Screenshots

Sample Settings
Behavior Settings

Flat System Navigation App Bar
Tab Navigation App Bar with selected items

History

2013-10-25: Source code update V1.2.0.0
Crashes on Windows 8.1 – fixed.

2013-08-14: Source code update V1.1.0.0
Corrections on transition / animation of items in navigation bar.

2013-08-13: Source code update V1.0.0.1
Instance Factory Logo changed.

Links

Click here to download the source code.

Windows 8 User Experience Guidelines

Dev Center UX Guide

Forum thread How to capture screen in Metro app??

.NET / RT implementation DirecX implementation SharpDX

Create Global AppBar in Windows Store Apps Using XAML/C#

The Quickstart: Static gestures

Forum thread Right tapped visual feedback rectangle

Forum thread Failed to start tracking the pointer because it is already being tracked

Implement Settings Popup Pages for Windows Store Apps

Microsoft Advertising Services AdControl Error Handling in XAML/C#

Preface

The Do’s + Don’ts of the Advertising SDK say “DO plan for times when no ads are available.” The links of that item leads to the ErrorCode enumeration and a rudimentarily error handling sample, writing text to debug output.

In this post, I will show an error handling where the AdControl is replaced by a TextBlock when an error occurs. Of course, this is still not a high sophisticated error handling. But it might give an idea what to do when no ad is available.

Ian Ferreira suggests in his blog post Keep Users First By Using These Resources For Ad Control Error Handling to hard code a house ad into the real-estate where an ad will appear.

Error Handling by Convention

The error handling is based on naming conventions. What it does is looking for a TextBlock having a name matching the naming pattern.

Following the convention, the name of the TextBlock has to be the name of the AdControl to be replaced, extended by ErrorTextBlock.

Sample: The name of the AdControl receiving an error is AdControlBottom. According to the naming convention, the name of the TextBlock to handle the error is AdControlBottomErrorTextBlock.

This makes it easy to implement a search for the correct replacement control. No additional properties need to be defined for the AdControl. And it follows MVC’s “Convention instead of Configuration” approach.

When an error occurs, the AdControl is made invisible, while the TextBlock at the same position will become visible. To make sure the design of the page does not change, the control that replaces the AdControl must have the same size as the AdControl.

In the sample app, just the name of the error-causing control, the reason, and the error text is displayed, no matter what the error code is. In real world scenarios, one should handle different errors differently. For example, just because an ad cannot be refreshed, I would not replace the existing one.

Here is how the handler is implemented:

protected virtual void OnAdControlErrorOccurred
  (
  object sender,
  AdErrorEventArgs args
  )
{
  AdControl adControl = sender as AdControl;

  // If event is not thrown by an Ad Control, do nothing
  if (adControl == null)
  {
    return;
  }

  // Just write out an error message.
  Debug.WriteLine("AdControl error (" + adControl.Name + "): " 
    + args.Error + " ErrorCode: " + args.ErrorCode.ToString());

  // Replace adControl by TextBlock showing error message.
  // Find the TextBlock by naming conventions. 
  // The name of the TextBlock is the name of the AdControl plus "ErrorTextBlock".
  TextBlock textBlock = FindName(
    String.Format("{0}ErrorTextBlock", adControl.Name)) 
  as TextBlock;

  if (textBlock == null)
  {
    return;
  }

  // Hide the AdControl
  adControl.Visibility = Visibility.Collapsed;

  // Show the TextBlock and copy properties.
  textBlock.Visibility = Visibility.Visible;

  textBlock.Height = adControl.Height;

  textBlock.Width = adControl.Width;

  // Set some text.
  textBlock.Text = String.Format("Sorry!{0}"
    + "Can't show AdControl '{1}'.{0}{0}ErrorCode: {2}{0}{0}ErrorMessage: {3}", 
    Environment.NewLine, adControl.Name, args.ErrorCode, args.Error.Message);
}

Please have a look at the sample code to see the XAML implementation. You can look at SubPages/SamplePage300x250.xaml, SubPages/SamplePage300x600.xaml, or SubPages/ SamplePageMultiple.xaml.

Sample Code

The sample code is part of the post Configure Microsoft Advertising Services’ AdControl using XAML/C#.

Links

Ads in Apps for Windows 8

AdControl Error Handling

AdControl ErrorCode Enumeration

Configure Microsoft Advertising Services’ AdControl using XAML/C#

Preface

The Microsoft Advertising SDK for Windows 8 allows developers to show ads in their apps. When you look at the walkthrough for putting ads in an app using XAML/C#, you can see that you have to set the ApplicationId and AdUnitId property of each AdControl control in your app.

For testing purposes, Microsoft has defined the ApplicationId d25517cb-12d4-4699-8bdc-52040c712cab and several AdUnitIds (can be found on the Test Mode Values page). These values are required in case you have no ids created in the pubCenter for yourself or in case you want to test your app in the emulator. (Well, on my machine the emulator showed productive ads even though the docs says it does not.)

Since I do not want to change my app every time I switch between the emulator and my dev machine, I was looking for a way to make these setting configurable.

Where to Store the Configuration Data?

In common .NET applications, the answer to this question is very simple: put it in the app.config. Unfortunately, for Windows Store apps the app.config approach is not available, or at least not offered by .NET for Windows Store apps.

So I built my own app.config mimic. Please have a look at the post Mimic app.config in Windows Store Apps for further details.

How to Change the Values During Runtime?

My first try was to define the AdControls in the XAML file and change both ApplicationId and AdUnitId in the constructor of the page’s class right after the call to PageClass.InitializeComponent. After receiving “NoAdAvailable” errors (which shows how important it is to implement an error event handler for AdControls), I had a look at the documentation.

In the remarks to the AdUnitId property the docs says that “This property can be set only when the AdControl is instantiated using the default constructor. Once set, this property cannot be modified.” The ApplicationId can be changed whenever you want. But that won’t help, because ApplicationId and AdUnitId are strongly tied together. Means, an AdUnitId is only valid in conjunction with its corresponding ApplicationId.

This means I cannot change the AdUnitId of all the AdControls that are defined in the XAML. Bad news? Not that bad – because we can also create UI controls during runtime, not only in XAML!

The AdControl Replacement Approach

After playing around a little bit I was choosing a replacement approach. This means that I define AdControls in XAML, and replace them during page initialization with those AdControls having the correct values for Application- and AdUnitId.

I prefer this approach because it offers the ability to check the look of the page also during design time, not only at runtime. So it is much easier to see if the page looks good. This requires me to set the (matching) height and width of the AdControls properly both in the XAML and configuration.

There is one prerequisite to use the replacement approach the way I implemented it: the AdControl to be replaced has to be a child control of a Panel (or derived class). Otherwise it is not possible to put the new AdControl at the place where the old one was.

The definition of the required config values is encapsulated by the class AdControlConfigData. The class looks like this:

public class AdControlConfigData
{
  [XmlAttribute]
  public string AdControlName { get; set; }

  [XmlAttribute]
  public string AdUnitId { get; set; }

  [XmlAttribute]
  public double Height { get; set; }

  [XmlAttribute]
  public double Width { get; set; }
}

The corresponding serialized data in the app.config looks like this:

<AdControlConfigData AdControlName="AdControl300x600" 
  AdUnitId="10043030" Width="300" Height="600"/>

The value of the ApplicationId is not part of this container. It is defined as a simple and single value in the app.config, since it is the same for all AdControls.

Replace the AdControls

In the sample code, I created a class called AdControlContainingPage, which is derived from LayoutAwarePage. This class is the base class of all pages containing AdControls. It holds all the functionality required to replace them, plus a basic handler for AdControl errors.

The XML config data is read by the ConfigurationManager class introduced in the Mimic app.config in Windows Store Apps post, also the XmlDeserialize used later.

For the sample app, the content of the app.config looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<!-- Configuration settings for Debug Build -->
<configuration>
  <appSettings>
    <!-- Use Microsoft Advertising Services Test ApplicationId -->
    <add key="AdApplicationId" 
            value="d25517cb-12d4-4699-8bdc-52040c712cab"/>
  </appSettings>

  <AdControlConfigList300x600>
    <AdControlConfigData AdControlName="AdControl300x600" 
          AdUnitId="10043030" Width="300" Height="600"/>
  </AdControlConfigList300x600>

  <AdControlConfigList300x250>
    <AdControlConfigData AdControlName="AdControl300x250" 
          AdUnitId="10043056" Width="300" Height="250"/>
  </AdControlConfigList300x250>

  <AdControlConfigListMultiple>
    <AdControlConfigData AdControlName="AdControl160x600" 
          AdUnitId="10043136" Width="160" Height="600"/>
    <AdControlConfigData AdControlName="AdControl728x90" 
          AdUnitId="10042998" Width="728" Height="90"/>
  </AdControlConfigListMultiple>
</configuration>

The different AdControlConfigData entities are extracted by the method AdControlContainingPage.GetAdControlConfiguration, which is shown here:

private static List<AdControlConfigData> GetAdControlConfiguration
  (
  XmlDocument xmlConfig,
  string sectionName
  )
{
  List<AdControlConfigData> configDataList 
    = new List<AdControlConfigData>();

  XmlNodeList xmlConfigDataList 
    = xmlConfig.DocumentElement
      .SelectNodes(
        String.Format("./{0}/AdControlConfigData", sectionName));

  foreach (IXmlNode node in xmlConfigDataList)
  {
    AdControlConfigData configData 
     = XmlDeserializer.Deserialize<AdControlConfigData>(node);

    configDataList.Add(configData);
  }

  return (configDataList);
}

Now that we have the configuration settings as a list of objects, which is really easy to handle, we can go on to replace the controls. This is done by AdControlContainingPage.ReplaceAdControls.

private void ReplaceAdControls
  (
  List<AdControlConfigData> adControlConfigDataList,
  string adApplicationId
  )
{
  // iterate over the list of configured AdControls.
  foreach (AdControlConfigData configData in adControlConfigDataList)
  {
    // Find the AdControl to be replaced.
    AdControl oldAdControl 
      = FindName(configData.AdControlName) as AdControl;

    // If the oldAdControl is not found, we can't replace it. So try the next one.
    if (oldAdControl == null)
    {
      Debug.WriteLine(String.Format("AdControl name >{0}< not found", configData.AdControlName));
      continue;
    }

    // Get the parent of the adcontrol. Needs to be a kind of panel.
    Panel parent = oldAdControl.Parent as Panel;

    // If the parent is not a panel, try the next one.
    if (parent == null)
    {
      Debug.WriteLine(String.Format("AdControl name >{0}< is not placed inside a panel or derived class. AdControl cannot be replaced.",
        configData.AdControlName));
      continue;
    }

    // Keep the position of the old AdControl.
    int postion = parent.Children.IndexOf(oldAdControl);

    // and remove it
    parent.Children.RemoveAt(postion);

    // Create the new AdControl with the correct ApplicationId and AdUnitId.
    AdControl adControl = new AdControl()
    {
      ApplicationId = adApplicationId,
      AdUnitId = configData.AdUnitId, // From msdn: This property can be set only when the AdControl is instantiated. Once set, this property cannot be modified.
      HorizontalAlignment = HorizontalAlignment.Left,
      Height = configData.Height,
      IsAutoRefreshEnabled = true,
      VerticalAlignment = VerticalAlignment.Top,
      Width = configData.Width
    };

    // Add the error hander
    adControl.ErrorOccurred += OnAdControlErrorOccurred;

    // Add the new control to the parent at the correct position.
    parent.Children.Insert(postion, adControl);
  }
}

The orchestration of these activities is done by AdControlContainingPage.SetupAdControls, which looks as follows:

protected async void SetupAdControls
  (
  string configSectionName
  )
{
  try
  {
    // Load the app.config.
    XmlDocument xmlConfig = await ConfigurationManager.GetConfig();

    // Get the AdApplicationId
    string adApplicationId 
      = ConfigurationManager
        .GetAppSettingsValue(xmlConfig, "AdApplicationId");

    // Extract the AdControl config data from the XML into a object list.
    List<AdControlConfigData> adControlConfigDataList 
      = AdControlContainingPage
        .GetAdControlConfiguration(xmlConfig, configSectionName);

    // Replace the AdControls
    ReplaceAdControls(adControlConfigDataList, adApplicationId);
  }
  catch (Exception e)
  {
    Debug.WriteLine(String.Format("Exception occurred:{0}{1}", 
      Environment.NewLine, e));
  }
}

One should call AdControlContainingPage.SetupAdControls right after the call of InitializeComponent of the derived class. In the sample, the derived classes are SamplePage300x250, SamplePage300x600, and SamplePageMultiple, which can be found in the SubPages folder of the solution.

The Sample Code

can be found here. To build and run the sample, you need to have the Microsoft Advertising SDK for Windows 8 installed. Have fun 🙂

Load It From The Windows Store

A slightly extented version of the sample can also be found in the Windows Store.

And finally, some screenshots of the sample app.

Main Page

Sample Page

Sample Page

Sample Page

Microsoft Advertising Services Test Mode Sample for Windows 8

Microsoft offers a very simple way to show advertising in Windows Store apps. A starting point is adsinapps.microsoft.com. The Microsoft Advertising SDK for Windows 8 can be found here: msdn.microsoft.com/en-us/library/hh506371%28v=msads.10%29.aspx.

The SDK docs lead you to a document, listing all the possible advertising test modes with their appropriate test values: msdn.microsoft.com/en-us/library/advertising-windows-test-mode-values%28v=msads.10%29.aspx.

Unfortunately, this page does not contain a sample to see all these ad services in action. So I created a quick & dirty one just to give me an idea of how the ads might look like. Here is a screenshot:

Ads in action

In my sample the following test mode values did not work as expected:
10043135: Video Ad with click to Full Screen Video (160×600)
10043056: Video Ad with click to Full Screen Video (300×250)
10042999: Video Ad with click to Full Screen Video (728×90).
The test mode value table states, that these services are videos, where a click opens another video. In my samples, these services only show images, opening a video when clicked. Maybe they will show images in production, which I hadn’t checked yet.

You can find the source code (VS 2012) here. To compile and run the sample, the Microsoft Advertising SDK for Windows 8 (can be found here: go.microsoft.com/?linkid=9815330) has to be installed. I was using the January 2013 version.

2013-07-23: Source code update V3.2
Minor design changes (logo & splash screen).

2013-07-10: Source code update V3.1
Minor design changes (headline & font).

2013-07-04: Source code update V3.0
Added new test mode id 10043030 (Image Ad 300×600); marked deprecated test mode ids as deprecated (10043124, 10043074, and 10043008 500×130)

2013-06-28: Source code update V2.0
Added scrolling to support screen resolutions less than 1920×1200

Installation Issue with Windows 7, Intel RAID Storage Controller and Advanced Format Disk

I had to re-install Windows 7 on one of my machines. It’s important to note that I had to re-install it, means, I had Windows 7 already running on that box.

The installation started as expected, created the partition, copied the files, started to setup the system. And when it comes to start the services, the installation aborted, telling “Windows Setup could not configure Windows on this computer’s hardware”.

That was a little bit surprising, since Windows 7 was running on this machine before. Searching the Web, I found no explanation. Then I remembered that I already had some trouble when I changed the system’s hard disk to a new one having the so called “Advanced Format”. In my case, I switched to a Western Digital WD5000BPKT. After that, Windows Update did not worked any more. This was solved by installing a new driver for the Intel RAID storage controller.

The installation image I was using was a Windows 7 RTM. So I decided to create a Windows 7 SP 1 installation image, hoping the driver fix was already included in SP 1. What can I say… the installation did its job 🙂

Summary: To run into this problem, your machine has to have an Intel RAID storage controller and an Advanced Format disk, where you want to install Windows 7 RTM on it. My solution was to use Windows 7 SP 1 instead.

The Knowledge Base article 2455673, which I found later, describes the details and shows two other resolutions. But I do prefer the SP 1 way.

Manage Wireless Networks in Windows 8

For whatever reason, Microsoft decided to remove the “Manage wireless networks” from the Network and Sharing Center.

As long as you want to manage the connection to a network you are already connected to, that’s no problem. Just right-click the properties of this connection.

Managing a not connected wireless network is possible, but not that simple. You have to become familiar with the netsh wlan command.
To list all the existing profiles, open a command prompt and enter

netsh wlan show profiles

From my point of view, the easiest way to manage an existing profile is to delete it via netsh and then re-create it using the Windows 8 UI tools. To delete a profile, use

netsh wlan delete profile profilename.