Home > C#, WinRT > Long running async operations within a Share request

Long running async operations within a Share request

02/04/2013

If we want to perform asynchronous operations within a Share request in a Windows Store app, we need to create a Deferral and call its Complete method to notify that data content for the asynchronous share is ready:

private async void DataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
    var request = e.Request;
    var deferral = request.GetDeferral();

    // Async operations ...
    await ...
    
    deferral.Complete();
}

If this way, we can use any async operations within the event handler. However, it’s important to remember that the DataRequest event is called as soon as the Share pane opens, so it must complete in a very short time, to prevent annoying waiting for the user. In fact, according to the documentation, this function must return a DataPackage object within 200ms to prevent the operation from timing out.

If we need more time to provide the share content (for example, we need to download an image from the Web), it’s a good practice to use the SetDataProvider method, with which we can specify a callback that will be called only when the target app is selected. In this callback, we can create the actual content we want to share. For example:

private void DataRequested(DataTransferManager sender, DataRequestedEventArgs e)
{
    var requestData = e.Request.Data;
    requestData.Properties.Title = "Long Running Share Example";
    requestData.Properties.Description = "Share with long running async operation";
    requestData.SetUri(new Uri("http://feeds.feedburner.com/bingimages"));

    // Specifies a callback to provide data for share, that will be invoked
    // when the target app is selected.
    requestData.SetDataProvider(StandardDataFormats.Bitmap, OnDataRequested);            
}

private async void OnDataRequested(DataProviderRequest request)
{
    var deferral = request.GetDeferral();

    // Gets the feed with last Bing images.
    var feedClient = new SyndicationClient();
    var feed = await feedClient.RetrieveFeedAsync
        (new Uri("http://feeds.feedburner.com/bingimages"));

    // Retrieves the Uri of the last image...
    var imageUri = feed.Items.FirstOrDefault().Links
        .Where(l => l.NodeName == "enclosure")
        .Select(l => l.Uri).FirstOrDefault();

    // ... and downloads it.
    var httpClient = new HttpClient();
    var bytes = await httpClient.GetByteArrayAsync(imageUri);

    var stream = new InMemoryRandomAccessStream();
    var writer = new DataWriter(stream.GetOutputStreamAt(0));
    writer.WriteBytes(bytes);

    await writer.StoreAsync();
    await writer.FlushAsync();            

    // Sets the image as Share content.
    request.SetData(RandomAccessStreamReference.CreateFromStream(stream));

    deferral.Complete();
}

Using this approach, the Share pane appears almost instantly. In fact, in the DataRequest method, we just set the basic properties, and then, on line 10, we use the SetDataProvider method to specify the callback to invoke when the target app is selected, and that is responsible for providing the actual data. Because we’re telling to Windows that the share content will be created later, we need to specify also the type of data. In this example, it is Bitmap, but other formats like Text, Html and Rtf are supported.

In the OnDataRequested method, we download an RSS feed containing the last Bing images, then we retrieve the first of them and set it as share content (line 39). Note that the Deferral object is still needed, but now is in the OnDataRequest method.

Categories: C#, WinRT
  1. No comments yet.
  1. 02/04/2013 at 13:19
Comments are closed.
%d bloggers like this: