Windows 8 XAML Tips - Popup.ShowAsync()

By Fons Sonnemans, posted on
2792 Views 2 Comments

In XAML applications you can use a Popup control to displays content on top of existing content. To show a Popup you must set the IsOpen property to true. You can subscribe yourself to the Closed eventhandler which is fired when the IsOpen property is (re)set to false. You can use this event to execute extra logic when the Popup is closed.

To make this easier I have created an ShowAsync() extension method which does this for you. I got my inspiration for this solution from this Awaiting Storyboard completion blog post by Nigel Sampson. He uses this technique to begin a storyboard using a BeginAsync() extension method.

private async void ButtonShowAsync_Click(object sender, RoutedEventArgs e) {
    (sender as Button).Content = "Clicked at " + DateTime.Now.ToString("HH:mm:ss");
    await this.popupTest.ShowAsync();
    (sender as Button).Content = "Closed at " + DateTime.Now.ToString("HH:mm:ss");
}

private void ButtonPopupIsOpen_Click(object sender, RoutedEventArgs e) {
    (sender as Button).Content = "Clicked at " + DateTime.Now.ToString("HH:mm:ss");
    this.popupTest.IsOpen = true;
    // You don't know when the popup was closed!
}

The ShowAsync() extension method uses an TaskCompletionSource. It allows us to create tasks behind the scenes and control whether they are completed, cancelled or failed. With this task you can build up some really handy mechanisms to improve the readability of your code.

static class Extensions {

    public static Task ShowAsync(this Popup popup) {

        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

        EventHandler<object> onClosed = null;
        onClosed = (s, e) => {
            popup.Closed -= onClosed;
            tcs.SetResult(true);
        };
        popup.Closed += onClosed;
        popup.IsOpen = true;

        return tcs.Task;
    }

}

The XAML used for this demo.

<Page x:Class="App4.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App4"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel Margin="20">

            <Button Content="Popup.IsOpen"
                    Click="ButtonPopupIsOpen_Click" />

            <Button Content="Popup.ShowAsync"
                    Click="ButtonShowAsync_Click" />

        </StackPanel>

        <Popup x:Name="popupTest"
               Margin="150"
               IsLightDismissEnabled="True">
            <Grid Background="Red"
                  Width="200"
                  Height="200">
                <Button Content="Close"
                        HorizontalAlignment="Center"
                        Click="ButtonClose_Click" />
            </Grid>
        </Popup>
    </Grid>
</Page>

ExtensionMethod.net website

I have published this extension method on www.extensionmethod.net. It is a website where c#, vb.net, f# and javascript extension methods are shared. You can also find my Chooser.ShowAsync() extension method which you can use to show a Windows Phone Chooser (AddressChooserTask, EmailAddressChooserTask, PhoneNumberChooserTask, PhotoChooserTask) using this technique.

private async void Button_Click(object sender, RoutedEventArgs e) {
    try {
        var c = new PhotoChooserTask();
        var result = await c.ShowAsync();
        var bi = new BitmapImage();
        bi.SetSource(result.ChosenPhoto);
        imagePhoto.Source = bi;
    } catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

Closure and download

I hope you like my solution. My demo is writen as a Windows Store app but you can also use it in Windows Phone, Silverlight and WPF. You can download my code below.

Cheers,

Fons

Download

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.

Leave a comment

Blog comments

jiltedflower

23-May-2014 1:12
Thank you!

Maddin

22-Oct-2014 10:21
This is exactly what i search for my project. Great work!!!