Using TaskCompletionSource in wraping event handler


Using TaskCompletionSource you can wrap any operation in to task, so that you can do anything you can with the task object. The TaskCompletionSource class is very important and today’s post will be explain how to wrap button click event in to TaskCompletionSource. With this wrap we will see how complicated operation behind click button handler can be simplified.

The for this blog post is simple Windows Store app shown on the picture below.

screen_sample2

When the Play Slides is clicked, Image slide is started which start animation of images. XAML code behind this app is listed here:

<Page.Resources>
    <Storyboard x:Name="animImageSlideIn">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
                                        Storyboard.TargetName="img">
            <EasingDoubleKeyFrame KeyTime="0" Value="900"/>
            <EasingDoubleKeyFrame KeyTime="0:0:2" Value="0" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Height="250" >
        <Button x:Name="playbtn" Height="50" Margin="0,5,0,5" Content="Play Slides" HorizontalAlignment="Center" Click="playbtn_Click"></Button>

        <Image x:Name="img" HorizontalAlignment="Center">
            <Image.RenderTransform>
                <CompositeTransform TranslateY="900" />
            </Image.RenderTransform>
        </Image>
    </StackPanel>
</Grid>

First, it will be presented  the implementation without TaskCompletionSource. The Play Slides Click event is the following code:

private async void  playbtn_Click(object sender, RoutedEventArgs e)
{
    int i = 1;

    EventHandler<object> handler = null;

    handler = delegate
    {
        if (i <= 3)
        {
            playbtn.Content = string.Format("Slide Image {0}",i);

            LoadSourceImage(i);

            animImageSlideIn.Begin();

            i++;
        }
        else
        {
            playbtn.Content = "Play Slides";
            animImageSlideIn.Completed -= handler;
            LoadSourceImage(0);

        }
    };

    animImageSlideIn.Completed += handler;
    handler(null,null);
}

As we can see from the listing above the code is pretty much long and little bit confused because we subscribe to the handler and call it as much as we reach the magic number of slides. Whe the number of slides is reached we unsubscribed from the handler and exit  the method.

Now implement the same functionality with the TaskCompletionSource class. The following listing shows the implementation:

private async void playbtn_Click(object sender, RoutedEventArgs e)
{

for(int i=1; i<=3; i++)
{
playbtn.Content = string.Format("Slide Image {0}",i);
LoadSourceImage(i);
await animImageSlideIn.RunAsync();
}

playbtn.Content = "Play Slides";
}

As we can see the implementation is very simple and concise. in for loop we call LoadSourceImage then asynchrony run animation.

The source code of the demo can be found by clicking the image below:

This blog post is inspired by Stephen Toub //build/ session.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s