IsTabStop Changes ListView ‘s Focusable Behaviour in Windows Store Apps

The Issue

Using the Factory Commander, I noticed some strange behavior.

I opened a folder with more items than can be displayed on the screen on the left side. Then I scrolled to the last item of the list and switched to the right list. There, I moved up or down one folder level (goto parent or child folder). The item list on the right side gets refreshed, and, to my surprise, the list on the left side scrolled up. It did so every time I moved up or down one level until the first item of the left list was displayed. Switch back to the left list, the list scrolls down to the focused last item itself.

I was able to reproduce this behavior with a simple Windows Store app having just two ListView controls, without any additional logic. So it seems to be a general issue, independent from the Factory Commander implementation.

The Solution

It took me some time, but after a while I found the (or one of the possible) solution. By default, the IsTabStop property of a ListView is set to false. Changing it to true solved my issue. It seems that setting this property enables the ListView to keep the focus even if there are no items in the list.

In WPF, there are two different properties: Focusable and IsTabStop.

Focusablegets or sets a value that indicates whether the element can receive focus“, while IsTabStopgets or sets a value that indicates whether a control is included in tab navigation.

The Control (base class of ListView) in WPF contains both properties, while the Control implementation for Windows Store apps lacks of the Focusable property. Seems the “.NET for Windows Store apps” framework team at MS decided that this property is “not related to developing Windows Store apps”.

Links

2,000 Things You Should Know About WPF; explanation of Focusable and IsTabStop in WPF

VisualTreeHelper Extensions for Windows Store Apps

Preface

The VisualTreeHelperprovides utility methods that can be used to traverse object relationships (along child-object or parent-object axes) in the visual tree of your app.

In this post I will show two extensions to VisualTreeHelper. Since you cannot create an instance of VisualTreeHelper, these are not extension methods from a technical point of view. But they do extend the functionality, so I call them extensions here.

FindChildByName Extension

This extension searches a child element in the visual tree by its name. Of course, there are other ways to find a control by its name, e.g. FrameworkElement.FindName.

I needed to find a control that was created during runtime. I had a ListView with an ItemsSource bound to an ObservableCollection<T>. An ItemTemplate was defined, containing several controls. And I needed to access one particular control inside of this generated ListViewItem. FrameworkElement.FindName did not found it, even though a x:Name was defined in the DataTemplate.

This lead to the first extension.

// Implemented by VisualTreeHelperExtensions
/// <summary>
/// Searches a child element in the visual tree by its name.
/// </summary>
/// <param name="parent">
/// The parent of the element.
/// </param>
/// <param name="name">
/// The name of the child to search for.
/// </param>
/// <param name="child">
/// Set to the child if found, otherwise <c>null</c>.
/// </param>
/// <returns>
/// <c>true</c> if the child was found, otherwise <c>false</c>.
/// </returns>
/// <remarks>
/// This method walks the visual tree recursively!
/// </remarks>
public static bool FindChildByName
  (
  DependencyObject parent,
  string name,
  out FrameworkElement child
  )
{
  // [Input parameter validation omitted]
  // Set the output first
  child = null;

  // Walk the tree
  int childrenCount = VisualTreeHelper.GetChildrenCount(parent);

  for (int childIndex = 0; childIndex < childrenCount; ++childIndex)
  {
    // Get the child
    DependencyObject childObject 
      = VisualTreeHelper.GetChild(parent, childIndex);

    // Convert it into a framework element
    FrameworkElement childElement 
      = childObject as FrameworkElement;

    // if successfull, check the name
    if (childElement != null
      && childElement.Name.Equals(name))
    {
      // We found it
      child = childElement;
      // get out
      return (true);
    }

    // If the child contains the element, get out
    if (VisualTreeHelperExtensions
        .FindChildByName(childObject, name, out child))
    {
      return (true);
    }
  }

  // if we got here, we hadn't found the child
  return (false);
}

As you can see from the code, the class that implements this method is called VisualTreeHelperExtensions. In case you like to use this extension too, make sure to give your extension class the same name. In case you want to give it another name, please change the call of VisualTreeHelperExtensions.FindChildByName at the end of the method to TheNameOfYourClass.FindChildByName.

FindFirstChildByType Extension

In another scenario, I needed to find the first child of a given type, independent from its name.

// Implemented by VisualTreeHelperExtensions
/// <summary>
/// Searches the first child element in the visual tree by its type.
/// </summary>
/// <param name="parent">
/// The parent of the element.
/// </param>
/// <param name="type">
/// The type of the child to search for.
/// </param>
/// <param name="child">
/// Set to the child if found, otherwise <c>null</c>.
/// </param>
/// <returns>
/// <c>true</c> if the child was found, otherwise <c>false</c>.
/// </returns>
/// <remarks>
/// This method walks the visual tree recursively!
/// </remarks>
public static bool FindFirstChildByType
  (
  DependencyObject parent,
  Type type,
  out FrameworkElement child
  )
{
  // [Input parameter validation omitted]
  // Set the output first
  child = null;

  // Walk the tree
  int childrenCount 
    = VisualTreeHelper.GetChildrenCount(parent);

  for (int childIndex = 0; childIndex < childrenCount; ++childIndex)
  {
    // Get the child
    DependencyObject childObject 
      = VisualTreeHelper.GetChild(parent, childIndex);

    // Convert it into a framework element
    FrameworkElement childElement 
      = childObject as FrameworkElement;

    // if successfull, check the type
    if (childElement != null
      && childElement.GetType() == type)
    {
      // We found it
      child = childElement;
      // get out
      return (true);
    }

    // If the child contains the element, get out
    if (VisualTreeHelperExtensions
      .FindFirstChildByType(childObject, type, out child))
    {
      return (true);
    }
  }

  // if we got here, we hadn't found the child
  return (false);
}

As said above, the class that implements this method is called VisualTreeHelperExtensions. In case you like to use this extension too, make sure to give your extension class the same name. In case you want to give it another name, please change the call of VisualTreeHelperExtensions.FindChildByName at the end of the method to TheNameOfYourClass.FindFirstChildByType.

Links

VisualTreeHelper class

Extension Methods (C# Programming Guide)

FrameworkElement.FindName

MessageBox for Windows Store Apps in C# / XAML

Preface

The replacement of MessageBox for Windows Store apps is the class MessageDialog.

This class is fine as long as you do not need more than three options the user can choose from. In technical words, MessageDialog allows only up to three commands. At the time of writing, this is not mentioned in the documentation of the Commands property, but in Quickstart: Adding a message dialog (Windows Store apps using JavaScript and HTML). In case you try to add more commands, an exception will be thrown: “The operation attempted to access data outside the valid range (Exception from HRESULT: 0x8000000B)

Of course, I do have the need for more than three commands. But the new control should not differ much from MessageDialog.

This results in the following requirements:

  • Show the message box by calling a ShowAsync method
  • Dynamically add IUICommand-based commands with a button label, an optional Action that will be executed when the user selects the command, and an optional id
  • Define a default cancel and default focus command
  • Show a message, an optional title, and an optional symbol
  • Reset the focus when the message box closes

ShowAsync & Dynamic Number of Buttons

This part was the most challenging one – and the funniest one too 🙂

The approach in the sample is this:

  • Have a popup torso, ready to be filled with title, message, symbol, and command buttons
  • Create one button per command, and attach a ManualResetEvent to each button
  • Start a new thread and let it wait for of one these wait handles to be signaled, i.e. wait for the user to push one of the buttons
  • Map the signaled wait handle to the corresponding action
  • Meanwhile, await the completion of the new thread
  • Execute the action by the main (UI) thread
  • Return the selected command
  • Reset the focus

Add Commands To Popup

Before it makes sense to bring up the message box, the buttons for the commands have to be added. And there needs to be some kind of connection between the buttons and the ManualResetEvents that are required for async usage. Here is the implementation.

// Implemented by MessageBox
private void AddCommandsToPopup()
{
  // In case no commmand is set, 
  // add a continue command without an action.
  if (CommandList.Count == 0)
  {
    CommandList.Add(new UICommand("Continue"));
  }

  // Remove exiting buttons 
  // in case ShowAsync was called more than once.
  ControlStackPanel.Children.Clear();

  // Create the delegate command used when a button is pressed
  DelegateCommand<ManualResetEvent> delegateCommand
    = new DelegateCommand(OnButtonPressed);

  // Iterate over the list of commands.
  foreach (IUICommand command in CommandList)
  {
    // Create a new wait handle for the command
    ManualResetEvent waitHandle = new ManualResetEvent(false);

    // Add it to the list.
    WaitHandleList.Add(waitHandle);

    // Create the button and attach the wait handle.
    Button button = new Button()
    {
      Command = delegateCommand,
      CommandParameter = waitHandle,
      Content = command.Label,
      Style = (Style)Application.Current.Resources["ButtonStyle"]
    };
    
    // Add the button to the popup
    ControlStackPanel.Children.Add(button);
  }
}

Handling Button Pressed

This command handler is really simple. The only intention is to let the waiting thread know that a button was pressed. This is done by signal the ManualResetEvent that is associated to button as the CommandParameter. That’s it.

// Implemented by MessageBox
private void OnButtonPressed
  (
  ManualResetEvent waitHandle
  )
{
  // Just signal the wait handle.
  waitHandle.Set();
}

Open the Message Box and Wait For User Input

Now that everything is prepared, we can go on and show the message box.

// Implemented by MessageBox
public async Task ShowAsync()
{
  // Add all commands to the command bar 
  // and create the matching wait handles.
  AddCommandsToPopup();

  // Keeps the index of the signaled wait handle.
  int signaledHandle = -1;

  // Find the control currently having the focus
  Control focusedControl 
    = FocusManager.GetFocusedElement() as Control;

  // Start the thread to wait for user input.
  Task waitForUserInputTask = Task.Run(() =>
  {
    // Wait for a handle to be signaled.
    signaledHandle 
      = ManualResetEvent.WaitAny(WaitHandleList.ToArray());
  });

  // Open the message box with a popup.
  Popup popup = PopupHelper.CreateFullScreenWithChild(this);

  // Set the focus on the defined button
  if (FocusCommandIndex >= 0
    && FocusCommandIndex < CommandList.Count)
  {
    ((Button)(ControlStackPanel.Children[FocusCommandIndex]))
      .Focus(FocusState.Programmatic);
  }

  // Wait for the wait thread to finish 
  // (one of the events to be signaled)
  await Task.WhenAny(new Task[] { waitForUserInputTask });

  // Free all wait handles.
  while (WaitHandleList.Count > 0)
  {
    WaitHandleList[0].Dispose();
    WaitHandleList.RemoveAt(0);
  }

  try
  {
    // Invoke the event handler of the selected command 
    // in case it is defined.
    if (CommandList[signaledHandle].Invoked != null)
    {
      CommandList[signaledHandle].Invoked
        .Invoke(CommandList[signaledHandle]);
    }
  }
  catch (Exception)
  {
    // re-throw any exception caused by the event handler.
    throw;
  }
  finally
  {
    // Make sure the popup will be closed.
    popup.IsOpen = false;

    // Release the message box from the popup
    popup.Child = null;

    // Reset the focus
    if (focusedControl != null)
    {
      focusedControl.Focus(FocusState.Programmatic);
    }
  }

  // Return the selected command
  return (CommandList[signaledHandle]);
}

That’s all the “magic” behind the async call. The very important implementation detail is that the sequence of the list of commands and wait handle have to be the same. Because ManualResetEvent.WaitAny returns the index of the signaled wait handle, it is very simple to call the corresponding event handler.

UI Controls Must Not Have Multiple Parents

To be able to call ShowAsync more than once on the same MessageBox instance, it is important to “release” the instance from its containing Popup. This is done by setting the Popup.Child to null.

In case the MessageBox is not released, an exception will be thrown when it is set as the child of a newly created Popup. The exception’s message is “Value does not fall within the expected range.” It is thrown by Popup.put_Child, means the setter of the Child property.

Well, the message does not seem very helpful to me. But after all, it makes sense that a UI control cannot have multiple parents. This is why the local Popup‘s Child is set to null after it is closed.

Using the MessageBox

In case the implementation details are a little bit confusing to you: relax. You don’t have to implement it yourself 😉 Focus on the usage. This should look very familiar to all users of MessageDialog.

// Implemented by MainPage
private async Task ShowInformationAsync()
{
  // Create the message box.
  MessageBox messageBox 
    = new MessageBox("This is an information.", 
        "Showing information", MessageBoxSymbol.Information);

  // Add the commands
  messageBox.CommandList.Add(new UICommand("OK", 
    action: null, commandId: "Confirmed"));
  messageBox.CommandList.Add(new UICommand("Abort", 
    action: null, commandId: "Aborted"));

  // Set the index of the focus and cancel command
  messageBox.FocusCommandIndex =
  messageBox.CancelCommandIndex = 1;

  // Show the message box
  string selectedCommandId 
    = (string)(await messageBox.ShowAsync()).Id;

  // Show the value selected
  ResultTextBlock.Text = selectedCommandId;
}

This sample uses the id of the selected command. The code contains samples using the event handler (action) and just the command too.

Please notice that the MessageBox implementation allows you to add a symbol. There is a definition for information, warning, and error included in the sample. In case you need some more, feel free to extent the code.

Disable AppBars

The MessageBox suppresses the opening of app bars, caused by a right click, as long as it is open. This is implemented by MessageBox by handling the RightTapped event. The Handled property of the event arguments is set to true.

It does not prevent the app bar from being opened when the user swipes in from the lower edge. There is no simple event to be handled for this gesture. One idea might be to handle the Opened event of the AppBar. When a MessageBox is open, the event handler should close the AppBar immediately.

Popup Dialog Basics

Please refer to BusyIndicator for Windows Store Apps in C# / XAML for details on popup dialog basics, like disabling the user to interact with the app.

For details on command delegates, please refer to Simple and Generic ICommand Implementation for Usage in XAML.

The Sample

… can be found here.

Information MessageBox

Warning MessageBox

Error MessageBox

Links

Quickstart: Adding a message dialog (Windows Store apps using JavaScript and HTML)

BusyIndicator for Windows Store Apps in C# / XAML

Simple and Generic ICommand Implementation for Usage in XAML

Threading Objects and Features

BusyIndicator for Windows Store Apps in C# / XAML

Preface

The BusyIndicator for Windows Store apps is a variation of the Busy-Indicating Dialog for Windows Store apps.

The motivation for creating such a control is almost the same. No such a control is available. And I want to make sure the user cannot start a new task while a running one has not finished, without blocking the UI thread or fiddling around with flags and disabled controls.

In contrast to the busy-indicating dialog, the busy indicator should not offer the ability to cancel the operation. This is because the underlying operation can’t be canceled too. And it cannot show progress, because the underlying operation is an indeterminate task.

This leads to the following requirements:

  • Disable user interaction (‘lock’ the app)
  • Give visual feedback to let the user know interaction is disabled
  • Do not block the UI thread
  • Show some progress indication

Also, it should comply with these Windows 8 user experience guidelines for indeterminate tasks:

  • If the task is modal — it blocks interaction until its completion — use the indeterminate progress ring style
  • Provide status text to the right of the progress ring
  • Make the progress ring the same color as its status text
  • Disable controls that user shouldn’t interact with while the task is running (matches with the first item of the requirements list above)

Disable User Interaction

Disabling the user to interact with the app is quite simple. Rob Caplan gave me the initial idea in his answer on how one might implement a modal popup. He suggested to use a full screen popup with a similar look to the MessageDialog.

Creating a full screen popup, or better say a popup having the current size of the app, disables the interaction with the app. No matter if the user clicks, taps, or uses the pen.

The first requirement is (almost) fulfilled.

Disable Keyboard Interaction

The reason for the ‘almost’ above is this. When you enable keyboard shortcuts in your app like this sample does, you still need some flag fiddling.

The BusyIndicator only disables interaction via the screen (mouse, touch, pen), but not via the keyboard. This is because there is no control embedded into the BusyIndicator that will handle keyboard input. I tried to handle the KeyDown events, but hadn’t received any.

So the bad news is, one has to set a flag when an indeterminate task starts, and evaluate that flag when another task should be started.

The busy-indicating dialog does not have that issue, because it contains a button to cancel the operation. This button captures the keyboard input.

Give Visual Feedback

Depending on how the full screen popup is implemented, the user might not recognize that the interaction is disabled.

Looking at MessageDialog, one might notice that the area that is not covered by the dialog itself is dimmed out.

To achieve this, a UserControl is implemented. In the sample code, this user control is named BusyIndicator and can be found in UI/Xaml/Popups.

BusyIndicator contains one Grid without any content. This Grid has a black background and an opacity of 0.4.

Setting an instance of BusyIndicator as the child of the Popup, the app’s window gets dimmed out when the Popup is opened. The second requirement is fulfilled.

Do Not Block the UI Thread

Because common UI controls are used, this requirement can be fulfilled without any additional effort.

Of course, one has to take care that the operation to be performed is non-blocking. Means it should be implemented in an asynchronous way. But this is independent from the implementation of the BusyIndicator.

Show Some Progress Indication

Now, the user sees that the interaction is disabled. But there is no information about what is going on. This might lead to the impression that the app has stopped working.

To show that there is something going on in the background, BusyIndicator contains a second Grid. It is something like a modal dialog, showing processing information. This Grid contains a ProgressRing and aTextBlock.

The ProgressRing is what the guidelines demands for indeterminate tasks. The TextBlock makes the control comply with the guideline to provide some status text.

The text will be set when the BusyIndicator is created. There is no binding required, since the text will not change while the BusyIndicator is active.

Make the Progress Ring the Same Color as Its Status Text

To comply with this UX guideline, the file Assets/ApplicationStyles.xaml contains the following SolidColorBrush definition:

<SolidColorBrush x:Key="IndicatorTextBrush" Color="#383838"/>

This brush is used by the TextBlock and the ProgressRing of the indicator to set the Foreground property.

Creating the Busy Indicator

The following code snippet shows all the steps that needs to be done to show the busy indicator.

// Implemented by BusyIndicator
public static BusyIndicator Start
  (
  string title
  )
{
  // Create a popup with the size of the app's window.
  Popup popup = new Popup()
  {
    Height = Window.Current.Bounds.Height,
    IsLightDismissEnabled = false,
    Width = Window.Current.Bounds.Width
  };

  // Create the BusyIndicator as a child, 
  // having the same size as the app.
  BusyIndicator busyIndicator = new BusyIndicator(title)
  {
    Height = popup.Height,
    Width = popup.Width
  };

  // Set the child of the popop
  popup.Child = busyIndicator;

  // Postion the popup to the upper left corner
  popup.SetValue(Canvas.LeftProperty, 0);
  popup.SetValue(Canvas.TopProperty, 0);

  // Open it.
  popup.IsOpen = true;

  // Return the BusyIndicator
  return (busyIndicator);
}

Prepare the Indeterminate Task

Because there are several steps to be done before an indeterminate task can start, this is encapsulated in a separate method.

// Implemented by MainPage
private BusyIndicator PrepareIndeterminateTask
  (
  string title
  )
{
  // Disable the app bar
  BottomAppBar.IsEnabled = false;

  // Lock the screen by starting the BusyIndicator
  BusyIndicator busyIndicator = BusyIndicator.Start(title);

  // Set the flag
  IsTaskInProgress = true;

  // return the indicator
  return (busyIndicator);
}

Please notice the fact that the app bar is disabled explicitly. The popup does not ‘block’ the app bar.

Cleanup

When the indeterminate task has finished, some cleanup is required.

// Implemented by MainPage
private void CleanUpIndeterminateTask
  (
  BusyIndicator busyIndicator
  )
{
  // close the BusyIndicator
  busyIndicator.Close();

  // Reset the flag
  IsTaskInProgress = false;

  // Enable the app bar
  BottomAppBar.IsEnabled = true;
}

Consider Windows Store App Lifecycle

In the article ‘The Windows Store App Lifecycle‘, Rachel Appel points out that “Windows 8 is changing how and when applications run”. In fact, it does!

Unlike desktop applications, Windows 8 suspends Windows Store apps (after a few seconds) when the user switches to another app. No matter what the app is currently doing. You cannot keep the app ‘alive’.

One should be aware of this. It means the user has to wait for long running operation to complete, and should not switch to another app meanwhile. This is kind of ‘blocking’ the device. Keeping this in mind, one should think twice before using Windows Store apps to execute long running operations, e.g. copy gigabytes of data.

Yes, there are background tasks available. But you cannot trigger them from within your app. So the usage is limited.

The Sample

… can be found here.

Screenshot

Screenshot

Links

Busy-Indicating Dialog for Windows Store apps

Forum question Modal popup

Download Windows 8 User Experience Guidelines for Windows Store apps

The Windows Store App Lifecycle

Background Tasks

Forum question ‘Trigger background task manually

Busy-Indicating Dialog for Windows Store Apps in C# / XAML

Preface

Some of you might know the BusyIndicator from the WPF Toolkit or from Silverlight.

I was using this control in Silverlight to disable user interaction while the application was performing some long running operations. This makes it really easy to make sure the user will not start a new task while another has not yet finished. And – very important – it does not block the UI thread, so the application does not seem to be unresponsive to the operation system.

Microsoft does not offer such a control for Windows Store apps. But even in a Windows Store app I needed to make sure the user ‘waits’ for the completion of a task, before a new is started. And I do not wanted to implement this by adding a flag telling no new task can be started (and/or disable controls based on that flag, …).

So what I wanted was a control that meets the following requirements:

  • Disable user interaction (‘lock’ the app)
  • Give visual feedback to let the user know interaction is disabled
  • Do not block the UI thread
  • Show some progress indication
  • Enable the user to cancel the operation

Disable User Interaction

Disabling the user to interact with the app is quite simple. Rob Caplan gave me the initial idea in his answer on how one might implement a modal popup. He suggested to use a full screen popup with a similar look to the MessageDialog.

Creating a full screen popup, or better say a popup having the current size of the app, and setting the focus to that popup, no interaction with the app is possible any more. No matter if the user clicks, taps, or uses the keyboard or pen.

The first requirement is fulfilled.

Give Visual Feedback

Depending on how the full screen popup is implemented, the user might not recognize that the interaction is disabled.

Looking at MessageDialog, one might notice that the area that is not covered by the dialog itself is dimmed out.

To achieve this, a UserControl is implemented. In the sample code, this user control is named BusyIndicatingDialog and can be found in UI/Xaml/Popups.

BusyIndicatingDialog contains one Grid without any content. This Grid has a black background and an opacity of 0.4.

Setting an instance of BusyIndicatingDialog as the child of the Popup, the app’s window gets dimmed out when the Popup is opened. The second requirement is fulfilled.

Do Not Block the UI Thread

Because common UI controls are used, this requirement can be fulfilled without any additional effort.

Of course, one has to take care that the operation to be performed is non-blocking. Means it should be implemented in an asynchronous way. But this is independent from the implementation of the BusyIndicatingDialog.

Show Some Progress Indication

Now, the user sees that the interaction is disabled. But there is no information about what is going on. This might lead to the impression that the app has stopped working.

To show that there is something going on in the background, BusyIndicatingDialog contains a second Grid. It is something like a modal dialog, showing the current processing state. It contains some TextBlocks and a ProgressBar.

These controls are bound to a view model, implemented by BusyIndicatingViewModel. This class can be found in ViewModels.

BusyIndicatingViewModel implements an event handler, OnItemProcessed. The class that implements the long-running operation, MainPage in this sample, needs to fire an appropriate event every time an item is processed (or when an update of the progress should be displayed). This event is implemented by MainPage.ItemProcessed.

And because BusyIndicatingViewModel implements the INotifyPropertyChanged interface (via its base class BindableBase), setting the properties in OnItemProcessed updates all the controls of the dialog.

Cancel the Operation

So far, we are able to stop user interaction with the app, give visual feedback on this, do not block the UI thread, and show how the operation proceeds. But maybe the user wants to cancel that operation, for whatever reason.

To enable the user to do this, a cancel button is added to the BusyIndicatingDialog. Pressing this button, the Cancel event is fired by the BusyIndicatingViewModel. This is implemented by binding the Command property of the Button control to the CancelOperationCommand of the view model.

Of course, just firing an event does not stop anything at all. The class that implements the long-running operation, MainPage in this sample, has to register an event handler on this event. The event handler (OnCancelOperation) sets a flag. This flag is evaluated on each iteration of the long-running operation. When it is set, the operation stops.

This feature makes the BusyIndicatingDialog ready to use.

Creating the Busy-Indicating Dialog

The following code snippet shows all the steps that needs to be done to show the busy-indicating dialog.

// Implemented by BusyIndicatingDialog
public static BusyIndicatingDialog LockScreen
  (
  int numberOfItemsToProcess
  )
{
  // Create a popup with the size of the app's window.
  Popup popup = new Popup()
  {
    Height = Window.Current.Bounds.Height,
    IsLightDismissEnabled = false,
    Width = Window.Current.Bounds.Width
  };

  // Create the busy-indicating dialog as a child, 
  // having the same size as the app.
  BusyIndicatingDialog dialog 
    = new BusyIndicatingDialog(numberOfItemsToProcess)
  {
    Height = popup.Height,
    Width = popup.Width
  };

  // Set the child of the popop
  popup.Child = dialog;

  // Postion the popup to the upper left corner
  popup.SetValue(Canvas.LeftProperty, 0);
  popup.SetValue(Canvas.TopProperty, 0);

  // Open it.
  popup.IsOpen = true;

  // Set the focus to the dialog
  dialog.Focus(FocusState.Programmatic);

  // Return the dialog
  return (dialog);
}

Prepare the Long Running Operation

Because there are several steps to be done before the long running operation can start, this is encapsulated in a separate method.

// Implemented by MainPage
private BusyIndicatingDialog PrepareLongRunningOperation
  (
  int numberOfItemsToProcess
  )
{
  // Disable the app bar
  BottomAppBar.IsEnabled = false;

  // Lock the screen
  BusyIndicatingDialog indicatorDialog 
    = BusyIndicatingDialog.LockScreen(numberOfItemsToProcess);

  // Set the view model as the event handler for processed items
  ItemProcessed += indicatorDialog.ViewModel.OnItemProcessed;

  // Set the handler for the cancel event.
  indicatorDialog.ViewModel.Cancel += OnCancelOperation;

  // Reset the flag for canceling the operation.
  CancelOperation = false;

  // return the dialog
  return (indicatorDialog);
}

Please notice the fact that the app bar is disabled explicitly. The popup does not ‘block’ the app bar.

Cleanup

When the long running operation has finished, some cleanup is required.

// Implemented by MainPage
private void CleanUpLongRunningOperation
  (
  BusyIndicatingDialog indicatorDialog
  )
{
  // Operation has finished => deregister the event handler 
  // so the garbage collector can release the dialog
  ItemProcessed 
    -= indicatorDialog.ViewModel.OnItemProcessed;

  // close the dialog
  indicatorDialog.Close();

  // Enable the app bar
  BottomAppBar.IsEnabled = true;
}

Additional Considerations

I consider this implementation to be useful in cases where many items (or tasks) should be processed sequentially, while the processing of each single item does not take too long. Having one task that takes very long, no progress can be displayed and no cancelation is possible. If you have to cover such a scenario, I think you need to find another solution.

One thing really important is to give the UI thread a chance to update the dialog control and react on user input. To do so, you should add an await Task.Delay(1); between the processing of each item. Otherwise, in case the processing of the single item is really fast, the dialog might not be updated and(!) pressing the cancel button does not have any effect.

Consider Windows Store App Lifecycle

In the article “The Windows Store App Lifecycle“, Rachel Appel points out that “Windows 8 is changing how and when applications run”. In fact, it does!

Unlike desktop applications, Windows 8 suspends Windows Store apps (after a few seconds) when the user switches to another app. No matter what the app is currently doing. You cannot keep the app ‘alive’.

One should be aware of this. It means the user has to wait for long running operation to complete, and should not switch to another app meanwhile. This is kind of ‘blocking’ the device. Keeping this in mind, one should think twice before using Windows Store apps to execute long running operations, e.g. copy gigabytes of data.

Yes, there are background tasks available. But you cannot trigger them from within your app. So the usage is limited.

The Sample

can be found here.

Main screen

Processing

Links

Forum question Modal popup

Simple and Generic ICommand Implementation for Usage in XAML

The Windows Store App Lifecycle

Background Tasks

Forum question ‘Trigger background task manually

Simple and Generic ICommand Implementation for Usage in XAML

Preface

The Commanding Overview says “Commanding is an input mechanism in Windows Presentation Foundation (WPF) which provides input handling at a more semantic level than device input. Examples of commands are the Copy, Cut, and Paste operations found on many applications.

Well, one should extent the definition and mention Windows Store apps too. Commanding is not limited to WPF.

When looking for a sample implementation that could be used in Windows Store apps too, I found this forum post: ICommand and MVVM.

The implementation looked quite easy to me, but lacks of type safeness from my point of view.

So I extended the DelegateCommand class from this post to be more typesafe.

Generic ICommand Implementation

/// <summary>
/// Generic implementation of <see cref="ICommand"/>.
/// </summary>
/// <typeparam name="T">
/// Type of the parameter the command expects.
/// </typeparam>
/// <remarks>
/// Copied from http://social.msdn.microsoft.com/Forums/en-US/f457c906-56d3-49c7-91c4-cc35a6ec5d35/icommand-and-mvvm
/// </remarks>
public class DelegateCommand<T> : ICommand
{
  #region Private Properties

  /// <summary>
  /// Gets / sets the action to be executed.
  /// </summary>
  private Action<T> ExecuteAction { get; set; }

  #endregion Private Properties


  #region Public Events

  /// <summary>
  /// Occurs when changes occur that affect whether 
  /// the command should execute.
  /// </summary>
  public event EventHandler CanExecuteChanged;

  #endregion Public Events


  #region Public Constructors

  /// <summary>
  /// Initializes a new instance of <see cref="DelegateCommand"/>
  /// with the action to be executed.
  /// </summary>
  /// <param name="executeAction">
  /// Action to be executed.
  /// </param>
  public DelegateCommand
    (
    Action<T> executeAction
    )
  {
    ExecuteAction = executeAction;
  }

  #endregion Public Constructors


  #region Public Methods

  /// <summary>
  /// Determines whether the command can execute in its current state.
  /// </summary>
  /// <param name="parameter">Data used by the command.</param>
  /// <returns>
  /// <c>true</c> if this command can be executed; 
  /// otherwise, <c>false</c>.
  /// </returns>
  public bool CanExecute
    (
    object parameter
    )
  {
    return true;
  }

  /// <summary>
  /// Invokes the method to be called.
  /// </summary>
  /// <param name="parameter">Data used by the command.</param>
  public void Execute
    (
    object parameter
    )
  {
    ExecuteAction((T) Convert.ChangeType(parameter, typeof(T)));
  }

  #endregion Public Methods
}

Usage

This class is used something like this:

public class MyViewModel
{
  …
  public ICommand SomeMethodCommand { get; private set; }
  …
    public MyViewModel ()
    {
      // Set the command.
      SomeMethodCommand = new DelegateCommand(SomeMethod);
    }
  …
    public void SomeMethod
      (
      bool value
      )
    {
      // Do something
    }
}

The usage in XAML is like this:

<Button Content="Invoke SomeMethod" 
  Command="{Binding SomeMethodCommand}" 
  CommandParameter="true"/>

where the DataContext of the page is set to an instance of MyViewModel.

Limitations of the Implementation

As said, this is a simple implementation of ICommand.

It does not evaluate the value passed to CanExecute. And it does not fire an event in case the CanExecute state changes (which is not implemented here too).

Links

Commanding Overview

Forum Post ICommand and MVVM

Using Windows Store App Resource Libraries in C# / XAML

Introduction

Given there is a Windows Store app. Some of the resources that this app needs are part of a library. This library contains a XAML file (ApplicationStyles.xaml) for application specific styles and the StandardStyles.xaml that is generated when a new Windows Store App (XAML) project is created. ApplicationStyles.xaml uses StandardStyle.xaml. Means, some styles defined in this file are based on styles that are defined in StandardStyles.xaml. And of course, the styles defined in the library will be used by XAML files that are located in the app.exe.

Scenario

Referencing in App.xaml of App.exe

The App.xaml of the app.exe only needs to reference to ApplicationStyles.xaml of the lib.

<Application.Resources>
  <ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
      <ResourceDictionary
        Source="ms-appx:///InstanceFactory_ResourceLib/Assets/ApplicationStyles.xaml"/>
    </ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</Application.Resources>

This means the file ApplicationStyles.xaml is located in the directory Assets of a library named InstanceFactory_ResourceLib.

The way to reference the resource dictionary of a lib in Windows Store apps differs from referencing in WPF or Silverlight. In WPF / Silverlight, the Source attribute would be set to /InstanceFactory.ResourceLib;component/Assets/ApplicationStyles.xaml.

The obvious difference is the usage of ms-appx URI prefix. Also, there is no separation of the library name (name of the output file) and the path the the XAML file (‘;component‘ in WPF / Silverlight).

What might be overseen is the fact that Windows Store apps can’t handle dot-separation of the library name. This is why the library in the Windows Store version contains an underscore, not a dot as separator.

It is also worth to mention that one have to put three dashes behind the ms-appx URI prefix.

Referencing Inside of Resource.lib

Because ApplicationStyles.xaml and StandardStyles.xaml are both part of the same assembly, and are located in the same directory, one might tend to include the StandardStyles.xaml into ApplicationStyles.xaml like this:

<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="StandardStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>

But this will not work. It might compile, but the app crashes on startup.

Although both files are part of the same library, you have to reference the StandardStyles.xaml the same way as if it was part of a different lib, means using the URI syntax shown above.

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary
     Source="ms-appx:///InstanceFactory_ResourceLib/Assets/StandardStyles.xaml"/>
  </ResourceDictionary.MergedDictionaries>

Please notice that this is only the case when ApplicationStyles.xaml of a library is used by App.exe. In case you have all styles defined inside of the exe itself, referencing works without URI syntax.

Checklist

To avoid exceptions in loading an external ResourceDictionary, especially those telling “Failed to assign to property ‘Windows.UI.Xaml.ResourceDictionary.Source’“, you have to comply with these preconditions:

Check Use the URI syntax having this format “ms-appx:///LibraryName/Directory/FileName.xaml

Check Use underscore to separate parts of the name of the assembly that contains the ResourceDictionary

Check Referencing inside the lib assembly also requires the URI syntax

Change Color of ToggleSwitch

Given you implement an app using the dark theme. This app contains some configuration values, which can be changed using a settings flyout. According to the design guidelines, the background of the settings flyout should be white.

Unfortunately, the default color theme for all controls is dark. So they are optimized for a dark background, but almost invisible on a white. To make a ToggleSwitch visible on the white background of the settings page while leaving the app’s theme dark, some theme resources needs to be overridden. This can be done inside the App.xaml, the StandardsStyles.xaml, or any other ResourceDictionary that is used by the app.

To make the ToggleSwitch visible on a white background while the app uses a dark theme, set these values:

<SolidColorBrush
 x:Key="ToggleSwitchCurtainBackgroundThemeBrush"
 Color="#FF4617B4" />
<SolidColorBrush
 x:Key="ToggleSwitchCurtainDisabledBackgroundThemeBrush"
 Color="Transparent" />
<SolidColorBrush
 x:Key="ToggleSwitchCurtainPointerOverBackgroundThemeBrush"
 Color="#FF5F37BE" />
<SolidColorBrush
  x:Key="ToggleSwitchCurtainPressedBackgroundThemeBrush"
  Color="#FF7241E4" />

<SolidColorBrush
  x:Key="ToggleSwitchDisabledForegroundThemeBrush"
  Color="#66000000" />
<SolidColorBrush
  x:Key="ToggleSwitchForegroundThemeBrush"
  Color="#FF000000" />

<SolidColorBrush
  x:Key="ToggleSwitchHeaderDisabledForegroundThemeBrush"
  Color="#66000000" />
<SolidColorBrush
  x:Key="ToggleSwitchHeaderForegroundThemeBrush"
  Color="#FF000000" />

<SolidColorBrush
  x:Key="ToggleSwitchOuterBorderBorderThemeBrush"
  Color="#59000000" />
<SolidColorBrush
  x:Key="ToggleSwitchOuterBorderDisabledBorderThemeBrush"
  Color="#33000000" />

<SolidColorBrush
  x:Key="ToggleSwitchThumbBackgroundThemeBrush"
  Color="#FF000000" />
<SolidColorBrush
  x:Key="ToggleSwitchThumbBorderThemeBrush"
  Color="#FF000000" />
<SolidColorBrush
  x:Key="ToggleSwitchThumbDisabledBackgroundThemeBrush"
  Color="#FF929292" />
<SolidColorBrush
  x:Key="ToggleSwitchThumbDisabledBorderThemeBrush"
  Color="#FF929292" />
<SolidColorBrush
  x:Key="ToggleSwitchThumbPointerOverBackgroundThemeBrush"
  Color="#FF000000" />
<SolidColorBrush
  x:Key="ToggleSwitchThumbPointerOverBorderThemeBrush"
  Color="#FF000000" />
<SolidColorBrush
  x:Key="ToggleSwitchThumbPressedBackgroundThemeBrush"
  Color="#FF000000" />
<SolidColorBrush
  x:Key="ToggleSwitchThumbPressedForegroundThemeBrush"
  Color="#FF000000" />

<SolidColorBrush
  x:Key="ToggleSwitchTrackBackgroundThemeBrush"
  Color="#59000000" />
<SolidColorBrush
  x:Key="ToggleSwitchTrackBorderThemeBrush"
  Color="Transparent" />
<SolidColorBrush
  x:Key="ToggleSwitchTrackDisabledBackgroundThemeBrush"
  Color="#1F000000" />
<SolidColorBrush
  x:Key="ToggleSwitchTrackPointerOverBackgroundThemeBrush"
  Color="#4A000000" />
<SolidColorBrush
  x:Key="ToggleSwitchTrackPressedBackgroundThemeBrush"
  Color="#42000000" />

For more options to change ToggleSwitch styles and templates, please have a look at ToggleSwitch styles and templates.

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

Implement Settings Popup Pages for Windows Store Apps

Preface

No, this is not the first sample to be found in the internet on this topic. Anyway, I decided to add another one because the two I was looking at (see links below) gave good ideas, but did not satisfied me at all.

Changes to App.xaml.cs

To begin, new items need to be added to the settings charm somehow. I did this by changing the app.xaml.cs. This is my starting point here.

First thing is to add a new using statement:

using Windows.UI.ApplicationSettings

Next, we need to know when to add our items to the settings charm. The class SettingPane has an event called CommandsRequested, which “… occurs when the user opens the settings pane. Listening for this event lets the app initialize the setting commands and pause its UI until the user closes the pane.” (description copied from MSDN docs).

So I added an event handler as the last statement of the App.OnLaunched method.

SettingsPane.GetForCurrentView().CommandsRequested 
  += OnSettingsCommandsRequested;

The handling method OnSettingsCommandsRequested is implemented in this sample like this:

private void OnSettingsCommandsRequested
  (
  SettingsPane settingsPane,
  SettingsPaneCommandsRequestedEventArgs args
  )
{
  args.Request.ApplicationCommands
    .Add(new SettingsCommand("about", "About", OnSettingsInvoked));

  args.Request.ApplicationCommands
    .Add(new SettingsCommand("popupHeaderBackgroundSlidesIn", 
     "Background slides in", OnSettingsInvoked));

  args.Request.ApplicationCommands
    .Add(new SettingsCommand("popupHeaderWithoutTransition", 
     "Header without transition", OnSettingsInvoked));

  args.Request.ApplicationCommands
    .Add(new SettingsCommand("popupHeaderWithTransition", 
     "Header with transition", OnSettingsInvoked));
}

As you can see, no matter which command is selected by the user, the method OnSettingsInvoked is called. Because the SettingsCommand constructor takes a settingsCommandId as first parameter, I am able to distinguish between the actions to be taken inside OnSettingsInvoked. Of course, one can also implement different handlers for each new command. I decided to us a single one in this sample because the action to be taken is very similar.

private void OnSettingsInvoked
  (
  IUICommand command
  )
{
  // Get the command id.
  string commandId = command.Id as string;

  // Has to be set, otherwise return.
  if (commandId == null)
  {
    return;
  }

  switch (commandId)
  {
    case "about":
      OpenSettingsPage<AboutPage>();
      break;
    case "popupHeaderBackgroundSlidesIn":
      OpenSettingsPage<HeaderBackgroundSlidesInPage>();
      break;
    case "popupHeaderWithoutTransition":
      OpenSettingsPage<HeaderWithoutTransitionPage>();
      break;
    case "popupHeaderWithTransition":
      OpenSettingsPage<HeaderWithTransitionPage>();
      break;
    default:
      break;

  }
}

The magic of opening a settings popup page is encapsulated by the method OpenSettingsPage<TPage>. It takes a type parameter to know what kind of popup page should be created. The type needs to be derived from SettingsPageBase to make sure the correct kind of page will be opened.

private void OpenSettingsPage()
  where TPage : SettingsPageBase, new()
{
  SettingsPopup = new Popup();

  SettingsPopup.IsLightDismissEnabled = true;
  SettingsPopup.Width = App.SettingsPopupWidth;
  SettingsPopup.Height = Window.Current.Bounds.Height;

  // Add the proper animation for the panel.
  SettingsPopup.ChildTransitions = new TransitionCollection();
  SettingsPopup.ChildTransitions.Add(new PaneThemeTransition()
  {
    Edge = (SettingsPane.Edge == SettingsEdgeLocation.Right) ?
           EdgeTransitionLocation.Right :
           EdgeTransitionLocation.Left
  });

  // Create a SettingsFlyout the same dimenssions as the Popup.
  TPage settingsFlyout = new TPage();
  settingsFlyout.Width = SettingsPopup.Width;
  settingsFlyout.Height = SettingsPopup.Height;

  // Place the SettingsFlyout inside our Popup window.
  SettingsPopup.Child = settingsFlyout;

  // define the location of our Popup.
  SettingsPopup.SetValue(Canvas.LeftProperty, 
    SettingsPane.Edge == SettingsEdgeLocation.Right 
    ? (Window.Current.Bounds.Width - SettingsPopup.Width) 
      : 0);
  SettingsPopup.SetValue(Canvas.TopProperty, 0);
  SettingsPopup.IsOpen = true;
}

It is worth to mention that SettingsPopup is a property of the App class. When implementing my first settings pages, I made this a local variable. But whenever I clicked somewhere into the main window while the settings page was open, my app crashes. I was not able to debug the problem. Even no UnhandledException handler helped me out.

SettingsPageBase

To avoid copy & paste development for the back button click handler, I created a base class for the settings pages. This is the class SettingsPageBase, located in the Common folder. The handler’s task is to close the Popup and re-open the settings charm when the back button is pressed.

protected virtual void OnGoBack
  (
  object sender,
  RoutedEventArgs args
  )
{
  // First close our Popup.
  Popup parent = this.Parent as Popup;

  if (parent != null)
  {
    parent.IsOpen = false;
  }

  // If the app is not snapped, then the back button shows the Settings pane again.
  if (ApplicationView.Value != ApplicationViewState.Snapped)
  {
    SettingsPane.Show();
  }
}

Mastering the Transition

When you open up the settings charm of this sample app, you will notice three different settings items: “Background slides in”, “Header without transition”, and “Header with transition”. You might ask why this. The answer is, that these are the three kinds of transitions I noticed when I was starting with settings pages. And it took me a while to figure out why my first attempts did not look the way I expected it (Header with transition).

Background slides in

When you open the “Background slides in” page, look at how the header block behaves, especially the background. It slides in, together with the button, text and logo. So when the page pops in, there is a tiny block on the left where the background color is the page’s background, not to the header’s.

The header controls slide in as expected, together with the content of the page, but that did not satisfied me. So I dig into the samples, because they did not behave that way. There, I found the next version:

Header without transition

On this page, the background of the header is set correctly. No slide in. But also, no slide in of the button, text, and image. Their position is fixed in relation to the upper left corner even when the page opens, while the describing text slides in. So still not satisfied (and not comply with the UX requirements).

Header with transition

This is the way I like it. The background is not sliding, while the header’s controls do, together with the page’s content.

To get this done, I had to change different things. When you find an easier way, I would be happy if you post it in a comment.

First, the root element of the page must not contain any Transitions definition. So no child element will slide in by default.

The settings pages consists of a Grid having two rows. One for the header, one for the content.

I put two Grids into the header row. The first, without transition, to have the background be in place when the page pops in. The second, containing the back button, text, and image, with a transition definition:

<Style x:Key="SettingsHeaderContentStyle" TargetType="Grid">
  <Setter Property="Transitions">
    <Setter.Value>
      <TransitionCollection>
        <EntranceThemeTransition/>
      </TransitionCollection>
    </Setter.Value>
  </Setter>
</Style>

This makes sure only the content of the header will slide in.

And because the root element of the page does not contain any transition definitions, also the content part, which is a StackPanel in the second row of the main Grid in my sample, needs the same transition definition.

All application-specific styles can be found in Common/ApplicationStyles.xaml.

UX Design Requirements

This app satisfies the following UX design requirements (all copied from Windows 8 User experience guidelines):

  • Place your settings Flyout on the same side of the screen as the charms. The charms and the settings window may be on the left side of the screen if the system’s text direction is right-to-left (like Arabic).
  • Settings Flyouts should be narrow (346 pixels) or wide (646 pixels).
  • Settings Flyouts should have a header that includes a back button, the name of the entry point that opened the Flyout, and the app’s icon (small one, 30x30px).
  • Use a light-dismiss surface, so that the settings Flyout disappears when the user touches anywhere on the screen outside of the surface.

The Dev Center sample “Settings Flyout” names a few more requirements, which I was not able to find in the guidelines. But they all seem reasonable, so I will list them here too:

  • Height has to be 100% of the screen.
  • Header is 80px high.
  • Header’s background must match the start tile’s background (from the manifest).
  • Flyout’s border must be darker than the header’s background (80% of its value). For instance, the background color in the example below is #999999, so the boarder color is rgb(0.8 * #99, 0.8 * #99, 0.8 * #99), which is rounded to #797979a.
  • The background of the main content area must be white. This can cause a problem if your app requests the dark theme; the text foreground color is white in the dark them, which renders it invisible when the background color is white. To request the light theme, set RequestedTheme="Light" in the app.xaml.
  • Both of the header’s and content’s controls must be animated.

The Sample Code

can be found here. To build an run the sample, you need Windows 8 and Visual Studio 2012.

Sample Screenshot

Links

Guidelines for app settings (Windows Store apps)

Store apps UX Guidelines Index

Dev Center Settings Flyout sample

Dev Center App settings sample (Windows 8)