Use Publicize.exe to Create Private Accessors for Visual Studio 2012+

Preface

Starting with Visual Studio 2012, private accessors cannot be created any more by the IDE. The post Home-made Private Accessor for Visual Studio 2012+ presents an approach on how to create private accessors using the class Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject.

Axel Mayer noted in the MSDN forums post How to create private accessors in VS 2012 that one can use the command line tool publicize.exe to create private accessors too.

Usage Of Publicize.exe

The usage of publicize.exe is quite simple. Open a command prompt, or a “VS2013 x86 Native Tools Command Prompt” to have the search path already set up, and run publicize.

In case you do not have the path set up correctly, the tool can be found at %Program Files (x86)%\Microsoft Visual Studio 11.0\Common7\IDE for Visual Studio 2012 or %Program Files (x86)%\Microsoft Visual Studio 12.0\Common7\IDE for VS 2013. At least, the tool is located there for the Ultimate edition of Visual Studio. I can’t tell which other editions contain it. Just have a look.

For a complete reference please refer to Using Publicize to Create a Private Accessor.

The usage in short: publicize.exe [options] input-assembly

The created assembly needs to be referenced by the test project. Of course, the source assembly – the assembly containing the classes to be tested – has to be referenced by the test project too.

publicize.exe creates classes named NameOfTheSourceClass_Accessor. In case the class to be tested is called MyClass, the accessor is named MyClass_Accessor.

publicize did work well for .NET 4.0 and .NET 4.5 assemblies in my tests. It also covered async and static methods.

Limitations

The docs mention that publicize does not support delegates or events.

From my tests I can add another limitation: publicize does not support Windows Store app assemblies (or I was not able to use it correctly). Running it against such an assembly I received these error messages (and a few more of the same type):

Cannot resolve dependency to Windows Runtime type ‘Windows.UI.Xaml.Application’. When using the ReflectionOnly APIs, dependent Windows Runtime assemblies must be resolved on demand through the ReflectionOnlyNamespaceResolve event.

Cannot resolve dependency to assembly ‘System.Runtime, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event.

Maybe you can give a hint on how this can be resolved. If so, please add a comment below. Thanks!

Resumé

As long as I don’t need accessors for Windows Store app assemblies, the usage of publicize.exe is my preferred way to generate private accessors.

In case publicize.exe does not support the source assembly type, I will created the private accessor myself as described by Home-made Private Accessor for Visual Studio 2012+.

Links

Home-made Private Accessor for Visual Studio 2012+

How to create private accessors in VS 2012

publicize.exe documentation

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

Position the PopupMenu for Drag And Drop Operations in Windows Store Apps

Preface

Sometimes it is helpful to open a PopupMenu when the user drops items on a destination, e.g. to ask the user if the items should be copied or moved.

I’d like to open the PopupMenu exactly where the user released the mouse / finger, means put the upper left corner to this point on the screen.

The DragEventArgs, passed by the Drop event, do not provide the absolute coordinates, but the drop point that is relative to an UIElement.

Get the Position of a UIElement

Having the relative position of the drop point, we just need the absolute position of an UIElement – i.e. the drop destination, e.g. a ListView – to be able to calculate the absolute position of the PopupMenu.

Unfortunately, UIElement does not have a Position property or a GetPosition method. But it offers a method to “return a transform object that can be used to transform coordinates from the UIElement to the specified object“: UIElement.TransformToVisual.

To be honest, from reading the docs I would not have found out how to get the absolute position of a control. Because the docs do not mention that it is possible to pass null as a parameter.

The MSDN Context Menu Sample helped me out. Using this sample, I created an extension method for UIElement:

/// <summary>
/// Returns the position of the element.
/// </summary>
/// <param name="instance">The instance to be used.</param>
/// <returns>The position of the element.</returns>
public static Point GetPosition
  (
  this UIElement instance
  )
{
  // Return the position.
  return (instance.TransformToVisual(null)
          .TransformPoint(new Point()));
}

Add a Little Helper

Now that we have the absolute position of the drop destination, we just need to add the relative position of the drop point to the get the place where to open the PopupMenu.

Because Point does not offer an add operator, I created another extension method to keep the code tidy:

/// <summary>
/// Add the summand to the point.
/// </summary>
/// <param name="instance">The instance to be used.</param>
/// <param name="summand">The summand to be added.</param>
/// <returns>A new instance with the sum.</returns>
public static Point Add
  (
  this Point instance,
  Point summand
  )
{
  // Add the coordinates.
  return (new Point(instance.X + summand.X, instance.Y + summand.Y));
}

Use the Extentions

Using these extensions, the handling of the Drop event of a ListView and positioning of the PoupMenu at the drop point might look something like this:

private async void OnListViewDropAsync
  (
  object sender,
  DragEventArgs args
  )
{
  // The sender has to be a UIElement
  UIElement uiElement = sender as UIElement;

  if (uiElement == null)
  {
    return;
  }
  
  // Get the drop point in relation to the sender
  Point relativeDropPoint = args.GetPosition(uiElement);

  // Calculate the absolute position of the popup, 
  // using the extensions
  Point dropPoint = uiElement.GetPosition().Add(relativeDropPoint);

  // Create a popup
  PopupMenu menu = new PopupMenu();
  menu.Commands.Add(new UICommand("Copy"));
  menu.Commands.Add(new UICommand("Move"));
  menu.Commands.Add(new UICommand("Cancel"));

  // Show it at the drop point
  await menu.ShowAsync(dropPoint);

  // Do something depending on the user's selection.
}

Links

Context Menu Sample

Considerations Regarding Building a FileSystemWatcher for Windows Store Apps

Preface

Unfortunately, .NET for Windows Store apps does not provide a FileSystemWatcher class. Nevertheless, one might want get notified when a folder, or file in a folder, has been changed.

This post presents some points I found worth to consider when I implemented a FileSystemWatcher for Windows Store apps.

Because the implementation of such a class depends on the kind of application it is used by, there is no code sample provided. The intention of this post is to give you some ideas about what I think should be considered when creating your own FileSystemWatcher.

Receive Notifications

This is the easy part. You just have to create a StorageFolderQueryResult, add a handler to its ContentsChanged event, and execute the query.

...

private StorageFolderQueryResult QueryResult { get; set; }

...

protected override async void OnNavigatedTo
  (
  NavigationEventArgs args
  )
{
  QueryResult = KnownFolders.PicturesLibrary
    .CreateFolderQueryWithOptions(new QueryOptions() 
      { FolderDepth = FolderDepth.Shallow });

  QueryResult.ContentsChanged += OnFolderContentChanged;

  try
  {
    await QueryResult.GetFoldersAsync(0, 1);
  }
  catch (Exception)
  {
    ...
  }
}
…
private void OnFolderContentChanged
  (
  IStorageQueryResultBase sender,
  object args
  )
{
  // Do something
}

It is sufficient to get just one folder. There is no linkage between the notifications and the number of items retrieved by the query. Calling GetFoldersAsync(0, 1) keeps the runtime impact to a minimum.

You can also call another method of StorageFolderQueryResult. The important thing is that the query executes at all.

Notification Content

The “content” of the notification is the notification itself and the folder that might have changed. Why “might”? Have a look below.

No. There is no further information sent by the event. You only get notified that something has changed. You do not get any information about what has changed.

Double Notification

At the time of writing, it seems that Windows 8 is not consistent in the way it fires the event.

In case a file is changed, one event is fired.

But in case a folder is changed (or created or deleted), two events are fired, with a timespan of one second. The timespan was observed on Windows 8 x64, Windows 8.1 x64, and Windows 8 RT. So it seems to be hardware-and OS-independent. For the latest news on this, please refer to StorageFolderQueryResult.ContentsChanged Fires Twice.

Notification Aggregation

In case many changes are made to the file system in a very short time – e.g. the user selects 100 files by the file explorer and deletes them – the behavior is unpredictable. I observed at minimum one event, but very often two, sometimes the second one with a delay of several seconds, sometimes even more events.

Notifications About Changes in Child Folders

As you can see from the code snipped above, I set the QueryOptions.FolderDepth to FolderDepth.Shallow. This means I only want to monitor changes of the given folder. I don’t care about changes in its child folders.

Unexpectedly, I also received notifications when the content of a child folder has changed. E.g. I was monitoring the Folder “Parent”, which contains a folder names “Child”. Creating a folder name “Grandchild” in the folder “Child” also fires an event, although I am monitoring “Parent”, not “Child”. Changing the content of “Grandchild” does not trigger an event.

Discover the Changes

Because the event does not give any information about what has changed, you need to discover it yourself.

To do so, the content of the observed folder prior to the change is needed, and the content after the change is needed too. This sounds simple, but there are some details to pay attention to.

Time Matters

To get the current content of a folder, I found no other way but to call StorageFolder.GetItemsAsync (or one of it variants to retrieve folders and files, GetFoldersAsync and GetFilesAsync).

Calling StorageFolder.GetItemsAsync() on my C:\Windows\System32 folder takes more than four seconds for ~3,100 items (Directory.GetFileSystemEntries took 0.1 second [100 milliseconds]). Four seconds are an eternity on a computer. Lots of additional changes might happen while I am trying to retrieve the current state. And in addition, one second after the first notification the duplicate will be fired, but nothing has changed.

Abort Content Retrieval

So there is the need to somehow be able to abort the retrieval of the current content list, in case a real additional change occurred.

I implemented this by reading the content in small chunks. StorageFolder offers methods to read items chunk wise. Between reading a chunk, I check a flag that is set when a new change occurred. If that flag is set, reading the content is aborted and restarted.

Reading the items chunk wise had no impact on the overall time required to retrieve the content of a folder.

Ignore the Double Notification

How can you tell if the current notification is a new one or the duplicate of the last? And what to do if there is a change 800 milliseconds after the last one occurred, but the notification duplicate has not arrived?

I can’t tell. That’s because the event does not give me any information about what has changed. In my app, I decided to ignore all additional notifications that were sent in less than a second after the “initial” notification was retrieved.

How to Compare the Content?

The list returned by StorageFolder.GetItemsAsync contains the folders first, and then the files. Trying to find differences by comparing the name only will fail, because the name of a folder should not be compared to the name of a file.

The consequence is to have the content lists separated by folders and files, or to find another way to make sure a folder is not compared to a file and vice versa.

It is also worth to mention that the list returned by StorageFolder.GetItemsAsync, and the folder / file variants, is sorted in natural sort order. I found C# comparison implementations on Stack Overflow.

Depending on what your app uses, comparing the name to detect changes might not be sufficient. In case the app relies on the file’s size or the last modified date too, there is additional code to be written, because these attributes needs to be collected in a second step (see Discover Properties of Storage Items in Windows Store Apps).

Conclusion

Creating a FileSystemWatcher for Windows Store apps is heavy stuff from my point of view. Even though I found a way to handle all the ‘challenges’, I do not really feel happy with my solution.

In case you have an approach that you think works good, please feel free to share it with us.

Links

NET for Windows Store apps

StorageFolderQueryResult documentation

StorageFolderQueryResult.ContentsChanged Fires Twice

Natural Sort Order

Natural sort order C# implementations

Discover Properties of Storage Items in Windows Store Apps

Factory Commander Available in Windows Store

Instance Factory’s file commander for Windows 8.1, Factory Commander, is now available in the Windows Store.

Factory Commander is a side by side file management app. Multiple tabs can be created to manage different file locations within the same window. Of course, copy, move, delete, permanent delete, and rename are supported. Folders can be created too. Strong keyboard support is integrated to be highly productive.

The Factory Commander monitors changes of folder content in the background and automatically updates the view.

The features are:

  • Side by side file management (dual pane)
  • Mutiple tabs
  • Background monitoring of folder content changes
  • Copy, move, rename, delete, permanent delete of files and folders
  • Folder creation
  • Strong keyboard support for higher productivity
  • Keyboard, mouse, and touch support
  • Launch files

You can find the Factory Commander here.

Factory Commander Screenshot

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

Discover Properties of Storage Items in Windows Store Apps

Preface

Sometimes it is helpful to discover some or all properties of storage items (StorageFile, StorageFolder).

These classes implement the interfaces IStorageItem and IStorageItemProperties.

IStorgeItem.GetBasicPropertiesAsync gets an object that provides access to the basic properties of an item. IStorageItemProperties.Properties gets an object that provides access to the content-related properties of an item.

To get the properties themselves, you need to call BasicProperties.RetrievePropertiesAsync respectively StorageItemContentProperties.RetrievePropertiesAsync. Both methods expect a list of property names to retrieve. But, at the time of writing this post, the docs do not give a hint on the question:

Which Properties are Available?

The complete list of possible property names can be found here.

But the list does not tell you which property is available on which storage item type. Images might have some other properties like text files or folders. Luckily, there is an undocumented way (undocumented at the time of writing) to get a list of all possible properties: Just pass an empty list. This returns a list of all properties of the current storage item both for basic and content-related properties.

Exceptions

Using the empty-list approach I noticed that there is at minimum one exception to the rule. Having a StorageFolder object of the root directory of a drive, e.g. c:\, the properties “System.ItemType” and “System.ItemTypeText” are not contained in the returned dictionary.

On the other hand, calling StorageItemContentProperties.RetrievePropertiesAsync(new string[] { "Type" }) on such a storage item, the result contains one entry with the key “System.ItemTypeText” with the value “Local Disk” (or “Network Drive”). Please notice that there is no property named “Type” contained in the list of available properties. The behavior is the same on Windows 8.1 Preview.

Discovering

Putting this together, one might think that the combination of basic and content-related properties gives the sum of all properties. Well, it does. But from what I saw during my tests, both lists contain the items. There is no difference between the basic and the content-related list. So you are free to use one of them (observed this on Windows 8.1 Preview too).

Tracing Basic Properties

To trace out all the properties using the basic interface, one might use this code:

private static async Task TraceBasicPropertiesAsync
  (
  IStorageItem storageItem
  )
{
  Debug.WriteLine(
    "{0}Tracing basic properties of storage item >{1}< / >{2}<", 
    Environment.NewLine, storageItem.Name, storageItem.Path);

  BasicProperties basicProperties 
    = await storageItem.GetBasicPropertiesAsync();

  Debug.WriteLine(String.Format(CultureInfo.InvariantCulture, 
    "DateModified {0:u} (UTC), ItemDate {1:u} (UTC), Size {2}", 
    basicProperties.DateModified, basicProperties.ItemDate, 
    basicProperties.Size));

  IDictionary<string, object> basicPropertyList 
    = await basicProperties.RetrievePropertiesAsync(new string[] { });

  foreach (KeyValuePair<string, object> property 
    in basicPropertyList.OrderBy(item => item.Key))
  {
    Debug.WriteLine("BasicProperty >{0}<: >{1}<", 
      property.Key, property.Value);
  }

  if (basicPropertyList.ContainsKey("System.Kind"))
  {
    foreach (string kind 
      in (string[]) basicPropertyList["System.Kind"])
    {
      Debug.WriteLine("BasicProperty kind >{0}<", kind);
    }
  }
}

Tracing Content-Related Properties

The code to trace all the content-related properites looks very similar:

private static async Task TraceContentRelatedPropertiesAsync
  (
  IStorageItem storageItem
  )
{
  Debug.WriteLine(
    "{0}Tracing content-related properties of storage item >{1}< / >{2}<",
    Environment.NewLine, storageItem.Name, storageItem.Path);

  // We need a different interface to access the 
  // content-related properties.
  IStorageItemProperties storageItemProperties 
    = storageItem as IStorageItemProperties;

  if (storageItemProperties == null)
  {
    Debug.WriteLine("IStorageItemProperties not implemented",
      Environment.NewLine);
    return;
  }

  IDictionary<string, object> propertyList 
    = await storageItemProperties.Properties
      .RetrievePropertiesAsync(new string[] { });

  foreach (KeyValuePair<string, object> property 
    in propertyList.OrderBy(item => item.Key))
  {
    Debug.WriteLine("Property >{0}<: >{1}<", 
      property.Key, property.Value);
  }

  if (propertyList.ContainsKey("System.Kind"))
  {
    foreach (string kind 
      in (string[]) propertyList["System.Kind"])
    {
      Debug.WriteLine("Property kind >{0}<", kind);
    }
  }

  // Handle missing properties for root directories.
  if (!propertyList.ContainsKey("System.ItemTypeText"))
  {
    IDictionary<string, object> missingList
      = await storageItemProperties.Properties
        .RetrievePropertiesAsync(
          new string[] { "System.ItemType", "System.ItemTypeText" });

    foreach (KeyValuePair<string, object> property 
      in missingList.OrderBy(item => item.Key))
    {
      Debug.WriteLine("Property >{0}<: >{1}<", 
        property.Key, property.Value);
    }
  }
}

There is an extra loop on the “System.Kind” property becaus it contains a string array.

Links

Windows Property System that can be set on Windows files

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