Visually Located

XAML and GIS

Creating a custom async dialog for your Win8 apps Part 2: CustomDialog

In Part 1 of this series I discussed how to create a custom async LoginDialog to use within your Windows Store apps. In this blog, I’ll explain how to turn that dialog into an async dialog that allows for custom content and works more like the MessageDialog. Most of the hard work was already completed in the LoginDialog. It has a constructor that takes content, a ShowAsync method that has the ability to show a dialog asynchronously, responds to a CancellationToken, it is shown as a Popup and responds to the size of the window changing and many more. To create the CustomDialog, I’ll start with the LoginDialog.

For the CustomDialog, I wanted to make it almost identical to the MessageDialog class except replacing the content parameter of the constructor from string, to object. For the new constructors, we’ll be using a ContentPresenter to place the custom content. The ContentPresenter will be created in code when the dialog is shown.

public CustomDialog(object content)
{
    Title = string.Empty;
    Commands = new List<IUICommand>();
    CancelCommandIndex = Int32.MaxValue;
    DefaultCommandIndex = Int32.MaxValue;
    HeaderBrush = new SolidColorBrush(Colors.White);
    Content = content;
}
 
public CustomDialog(object content, string title) : this(content)
{
    if (string.IsNullOrEmpty(title) == false)
    {
        Title = title;
    }
}

Matching the MessageDialog also meant added in custom commands to the dialog that allow for a custom action. Also want to make sure that the default and cancel buttons can be specified.

/// <Summary>
/// Gets or sets the index of the command you want to use as the default. This
/// is the command that fires by default when users press the ENTER key.
/// </Summary>
/// <Returns>The index of the default command.</Returns>
public int DefaultCommandIndex { get; set; }
 
/// <Summary>
/// Gets or sets the index of the command you want to use as the cancel command.
/// This is the command that fires when users press the ESC key.
/// </Summary>
/// <Returns>The index of the cancel command.</Returns>
public int CancelCommandIndex { get; set; }
 
/// <Summary>
/// Gets the set of commands that appear in the command bar of the message dialog.
/// </Summary>
/// <Returns>The commands.</Returns>
public IList<IUICommand> Commands { get; private set; }

When we create the buttons, we need to apply the properties from the custom commands and ensure that the user gets to do their custom action.

private UIElement CreateDialog()
{
    // Create the dialog
    ...
 
    if (Commands.Count == 0)
    {
        Button button = new Button();
        button.Style = buttonStyle;
        button.Content = "Close";
        button.MinWidth = 92;
        button.Margin = new Thickness(20, 20, 0, 20);
        button.Click += (okSender, okArgs) => CloseDialog(null);
        buttonPanel.Children.Add(button);
    }
    else
    {
        foreach (var command in Commands)
        {
            IUICommand currentCommand = command;
            Button button = new Button();
            button.Style = buttonStyle;
            button.Content = command.Label;
            button.Margin = new Thickness(20, 20, 0, 20);
            button.MinWidth = 92;
            button.Click += (okSender, okArgs) => CloseDialog(currentCommand);
            buttonPanel.Children.Add(button);
        }
    }
    ...
}
 
private void CloseDialog(IUICommand command)
{
    UnsubscribeEvents();
 
    if (command != null)
    {
        command.Invoked(command);
    }
    _popup.IsOpen = false;
    _taskCompletionSource.SetResult(command);
}

Now that the dialog has the ability to specify if there is a default and cancel button, we nee to make changes to the KeyDown event of the window.

private void OnKeyDown(object sender, KeyRoutedEventArgs e)
{
    // Only respond to Esc if there is a cancel index
    if ((e.Key == VirtualKey.Escape) && (CancelCommandIndex < Commands.Count))
    {
        OnCanceled();
    }
 
    // Only respond to Enter if there is a cancel index
    if ((e.Key == VirtualKey.Enter) && (DefaultCommandIndex < Commands.Count))
    {
        CloseDialog(Commands[(int)DefaultCommandIndex]);
    }
}

The rest of the CustomDialog is pretty much identical to the LoginDialog. You can download the source and sample application which has both the LoginDialog and CustomDialog in it. If you just want just the CustomDialog class you can download it from GitHub.