WhenAny: ponte entre o .NET Framework e o Tempo de Execução do Windows (C# e Visual Basic)

O exemplo deste tópico combina um tipo de Tempo de Execução do Windows que baixa feeds do blog de forma assíncrona com um método do .NET Framework que processa tarefas assíncronas na ordem em que são concluídas. Para obter mais informações sobre o tipo, consulte SyndicationClient. Para obter mais informações sobre o método, consulte Task.WhenAny.

Ao combinar esses recursos, você pode começar a baixar simultaneamente vários feeds do blog e processar os resultados conforme forem sendo concluídos. Se o download de um feed for mais rápido do que o outro, seus resultados aparecerão primeiro. Usando um método SyndicationClient, você pode baixar os feeds mais facilmente; usando o método Task.WhenAny, você pode facilmente identificar a próxima linha que está terminando de baixar.

Dica

Para executar o exemplo, você deve ter o Windows 8 instalado no seu computador.Além disso, se quiser executar o exemplo no Visual Studio, você também deverá ter o Visual Studio 2012, o Visual Studio 2013, Visual Studio Express 2012 para Windows 8 ou o Visual Studio Express 2013 para Windows instalado.

O código a seguir combina esses recursos do Tempo de Execução do Windows e do .NET Framework:

Try 
    Dim feedsQuery As IEnumerable(Of Task(Of SyndicationFeed)) =
        From uri In uriList
        Select client.RetrieveFeedAsync(uri).AsTask()
    ' AsTask changes the returns from RetrieveFeedAsync into tasks. 

    ' Run the query to start all the asynchronous processes. 
    Dim blogFeedTasksList As List(Of Task(Of SyndicationFeed)) = feedsQuery.ToList()

    Dim feed As SyndicationFeed

    ' Repeat the following until there are no tasks left: 
    '    - Grab the first one that finishes. 
    '    - Retrieve the results from the task (what the return statement  
    '      in RetrieveFeedAsync returns). 
    '    - Remove the task from the list. 
    '    - Display the results. 
    While blogFeedTasksList.Count > 0
        Dim nextTask As Task(Of SyndicationFeed) = Await Task.WhenAny(blogFeedTasksList)
        feed = Await nextTask
        blogFeedTasksList.Remove(nextTask)
        DisplayResults(feed)
    End While 

Catch ex As Exception
    ResultsTextBox.Text =
        "Page could not be loaded." & vbCrLf & "Exception: " & ex.ToString()
End Try
try
{
    IEnumerable<Task<SyndicationFeed>> feedsQuery =
            from uri in uriList
            // AsTask changes the returns from RetrieveFeedAsync into tasks. 
            select client.RetrieveFeedAsync(uri).AsTask();

    // Run the query to start all the asynchronous processes.
    List<Task<SyndicationFeed>> blogFeedTasksList = feedsQuery.ToList();

    SyndicationFeed feed;

    // Repeat the following until no tasks remain: 
    //    - Grab the first one that finishes. 
    //    - Retrieve the results from the task (what the return statement  
    //      in RetrieveFeedAsync returns). 
    //    - Remove the task from the list. 
    //    - Display the results. 
    while (blogFeedTasksList.Count > 0)
    {
        Task<SyndicationFeed> nextTask = await Task.WhenAny(blogFeedTasksList);
        feed = await nextTask;                    
        blogFeedTasksList.Remove(nextTask);
        DisplayResults(feed);
    }
}
catch (Exception ex)
{
    ResultsTextBox.Text =
        "Page could not be loaded.\n\r" + "Exception: " + ex.ToString();
}

O exemplo produz a saída se assemelha às linhas a seguir. Para cada blog, a exibição mostra o título do blog seguido por títulos e datas para postagens no blog.

Developing for Windows
     New blog for Windows 8 app developers, 5/1/2012 2:33:02 PM -07:00
     Trigger-Start Services Recipe, 3/24/2011 2:23:01 PM -07:00
     . . .
     Countdown to PDC10, 10/26/2010 4:11:28 PM -07:00

Extreme Windows Blog
     PDXLAN 20: “Epidemic” Custom PC by Jon Hansz, 7/30/2012 2:31:35 PM -07:00
     Samsung Notebook Series 9: Taking Thin and Light to the Extreme, 7/23/2012 12:06:03 PM -07:00
     . . .
     AMD Unveils A-Series APUs, 6/13/2011 9:34:01 PM -07:00

Blogging Windows
     Windows 8 has reached the RTM milestone, 8/1/2012 9:00:00 AM -07:00
     Windows 8 will be available on…, 7/18/2012 1:09:00 PM -07:00
     . . .
     More buzz from BUILD – Developers get their devices!, 9/13/2011 7:47:57 PM -07:00

Springboard Series Blog
     What to Expect in User Experience Virtualization Beta 2, 6/25/2012 11:03:27 PM -07:00
     Introducing Microsoft BitLocker Administration 2.0 Beta, 6/12/2012 8:08:23 AM -07:00
     . . .
     The Springboard Series Visits Lima, Peru, 11/18/2011 5:27:37 AM -08:00

O restante deste tópico oferece detalhes sobre como criar o exemplo e como ele funciona.

Você deve ter o Visual Studio 2012 e o Windows 8 instalado em seu computador para executar este aplicativo.

Este tópico contém as seções a seguir.

  • Opções de configuração para o exemplo
  • Entendendo o código inicial
  • Extensão do código para iniciantes
  • Baixando o código de iniciantes
  • Baixando o aplicativo concluído
  • Compilando o código para iniciantes
  • Compilando o aplicativo concluído
  • Tópicos relacionados

Opções de configuração para o exemplo

O exemplo se baseia no leitor do blog que é descrito em Início rápido: usando o operador await para a programação assíncrona. No entanto, o código para iniciantes desse tópico baixa vários feeds do blog em vez de apenas um.

O código inicial usa a funcionalidade Tempo de Execução do Windows para baixar os feeds de blog sequencialmente. Ou seja, os feeds de blog são baixados na ordem em que são listados em uma coleção de URLs. O aplicativo concluído adiciona funcionalidade do .NET Framework para baixar os feeds de blog na ordem em que eles são concluídos.

É possível configurar o exemplo de código em qualquer uma das seguintes maneiras:

  • Código inicial.

    • É possível baixar o código inicial seguindo as instruções em Baixando o código inicial.

    • É possível criar o código inicial você mesmo seguindo as instruções em Compilando o código inicial.

    • É possível examinar o código inicial sem implementá-lo rolando até Criando o código inicial.

  • Aplicativo concluído.

    • É possível baixar o aplicativo finalizado seguindo as instruções em Baixando o aplicativo finalizado

    • É possível compilar o aplicativo você mesmo seguindo as instruções em Criando o aplicativo concluído.

    • É possível examinar o aplicativo concluído sem implementá-lo rolando até Compilando o aplicativo concluído.

A seção Noções básicas sobre o código inicial discute os principais pontos da solução básica.

A seção Estendendo o código inicial mostra como modificar o código adicionando AsTask``2 e Task.WhenAny.

Entendendo o código inicial

O código inicial usa um método SyndicationClientRetrieveFeedAsync para baixar um feed de blog de cada URI em uma lista de URIs. Cada chamada ao método retorna uma instância IAsyncOperationWithProgress que representa uma operação assíncrona em andamento. Quando esperada, a operação assíncrona gera uma instância SyndicationFeed que contém informações sobre o feed baixado do blog.

O código define uma consulta que aplica RetrieveFeedAsync a cada entrada em uma lista de URIs. Quando executada, a consulta retorna uma coleção de instâncias de IAsyncOperationWithProgress.

Dim feedsQuery As IEnumerable(Of IAsyncOperationWithProgress(Of SyndicationFeed, 
                                                                RetrievalProgress)) =
                                                From uri In uriList
                                                Select client.RetrieveFeedAsync(uri)
IEnumerable<IAsyncOperationWithProgress<SyndicationFeed, 
    RetrievalProgress>> feedsQuery = from uri in uriList
                                     select client.RetrieveFeedAsync(uri);

ToList``1 executa a consulta e inicia os processos assíncronos, como mostra o código a seguir.

Dim blogFeedOpsList As List(Of IAsyncOperationWithProgress(Of SyndicationFeed, 
                                                           RetrievalProgress)) =
                                               feedsQuery.ToList()
List<IAsyncOperationWithProgress<SyndicationFeed, 
    RetrievalProgress>> blogFeedOpsList = feedsQuery.ToList();

Neste ponto, você tem uma lista de instâncias ativas de IAsyncOperationWithProgress . Você ainda deve esperar que cada instância obtenha os resultados finais.

O seguinte loop espera que cada instância IAsyncOperationWithProgress recupere os resultados de SyndicationFeed .

Dim feed As SyndicationFeed
For Each blogFeedOp In blogFeedOpsList
    ' The Await operator retrieves the final result (a SyndicationFeed instance) 
    ' from each IAsyncOperation instance.
    feed = Await blogFeedOp
    DisplayResults(feed)
Next
SyndicationFeed feed;
foreach (var blogFeedOp in blogFeedOpsList)
{
    // The await operator retrieves the final result (a SyndicationFeed instance) 
    // from each IAsyncOperation instance.
    feed = await blogFeedOp;
    DisplayResults(feed);
}

É possível examinar esta versão do programa na seção Criando o código inicial no final do tópico.

É possível encontrar mais informações sobre a programação com APIs Tempo de Execução do Windows assíncronos em Guia de Início Rápido: usando o operador de espera para programação assíncrona.

Extensão do código para iniciantes

O código inicial demonstra que o SyndicationClient facilita o download de feeds de blog. A etapa restante para a conclusão do exemplo é permitir que o aplicativo processe os feeds do blog na ordem de conclusão de seus downloads em vez da ordem na qual eles aparecem na lista de URIs.

A chave para realizar o aprimoramento é o método Task.WhenAny. Ao aplicar WhenAny a uma coleção de processos assíncronos, o método retorna o primeiro processo que conclui, minimizando o tempo que você deve esperar. Nesse exemplo, a ordem na qual informações de feed do blog aparecem não é importante. Se um download for lento, os resultados de outro blog podem ser exibidos primeiro. A situação aparece perfeita para WhenAny, exceto por um detalhe: WhenAny exige uma coleção de tarefas.

Chamando AsTask

WhenAny requer uma coleção de Task ou de instâncias de Task, mas o método SyndicationClient que baixa os feeds do blog retorna um instância de IAsyncOperationWithProgress. Portanto, o aplicativo deve ser a ponte entre os objetos IAsyncOperationWithProgress do Tempo de Execução do Windows e os objetos Task do .NET Framework.

O .NET Framework oferece métodos de extensão AsTask``2 para fazer a transição. Ao chamar AsTask em uma instância de IAsyncOperationWithProgress, o AsTask retorna uma tarefa que representa a operação assíncrona. A tarefa termina quando a instância correspondente de IAsyncOperationWithProgress é concluída e a tarefa tem o resultado ou a exceção da instância.

Portanto, você invoca apenas AsTask em cada instância de IAsyncOperationWithProgress retornada por RetrieveFeedAsync, à medida que o código a seguir for mostrado. O código renomeia variáveis para refletir a alteração nas tarefas e usa digitação explícita para maior clareza.

Dim feedsQuery As IEnumerable(Of Task(Of SyndicationFeed)) =
    From uri In uriList
    Select client.RetrieveFeedAsync(uri).AsTask()
' AsTask changes the returns from RetrieveFeedAsync into tasks. 

' Run the query to start all the asynchronous processes. 
Dim blogFeedTasksList As List(Of Task(Of SyndicationFeed)) = feedsQuery.ToList()
IEnumerable<Task<SyndicationFeed>> feedsQuery =
        from uri in uriList
        // AsTask changes the returns from RetrieveFeedAsync into tasks. 
        select client.RetrieveFeedAsync(uri).AsTask();

// Run the query to start all the asynchronous processes.
List<Task<SyndicationFeed>> blogFeedTasksList = feedsQuery.ToList();

Dica

AsTask executa uma função importante na programação assíncrona que você provavelmente não está ciente.O compilador usa AsTask sempre que você aplica um operador de espera a uma instância IAsyncAction ou IAsyncOperation, como mostrado pelo código a seguir.

Aplicando WhenAny

A última etapa da conversão é adicionar o método Task.WhenAny ao aplicativo. WhenAny é aplicado a uma coleção de tarefas (blogFeedTasksList) e retorna a primeira tarefa na coleção que está concluída. Mais especificamente, WhenAny retorna uma tarefa que, quando esperada, avalia a tarefa que tiver concluído primeiro.

A instrução a seguir chama WhenAny e espera o resultado. O código usa digitação explícita para mostrar o resultado com mais clareza.

Dim nextTask As Task(Of SyndicationFeed) = Await Task.WhenAny(blogFeedTasksList)
Task<SyndicationFeed> nextTask = await Task.WhenAny(blogFeedTasksList);

O código a seguir faz a mesma coisa que a declaração anterior, mas divide a operação em duas instruções para esclarecer o que acontece. A primeira declaração chama WhenAny e a segunda declaração aguarda o resultado.

' WhenAny returns a task that, when awaited, produces a task.
' Call:
Dim whenAnyTask As Task(Of Task(Of SyndicationFeed)) = Task.WhenAny(blogFeedTasksList)
' Await:
Dim nextTask As Task(Of SyndicationFeed) = Await whenAnyTask
// WhenAny returns a task that, when awaited, produces a task.
// Call:
Task<Task<SyndicationFeed>> whenAnyTask = Task.WhenAny(blogFeedTasksList);
// Await:
Task<SyndicationFeed> nextTask = await whenAnyTask;

Por fim, você deve aguardar nextTask para recuperar os resultados (uma instância de SyndicationFeed) da tarefa que tiver sido concluída primeiro. Em seguida, você deve remover nextTask da lista para que não a processe novamente.

feed = Await nextTask
blogFeedTasksList.Remove(nextTask)
feed = await nextTask;                    
blogFeedTasksList.Remove(nextTask);

Use um loop "while" para executar essas etapas para cada tarefa em blogFeedTasksList.

While blogFeedTasksList.Count > 0
    Dim nextTask As Task(Of SyndicationFeed) = Await Task.WhenAny(blogFeedTasksList)
    feed = Await nextTask
    blogFeedTasksList.Remove(nextTask)
    DisplayResults(feed)
End While
while (blogFeedTasksList.Count > 0)
{
    Task<SyndicationFeed> nextTask = await Task.WhenAny(blogFeedTasksList);
    feed = await nextTask;                    
    blogFeedTasksList.Remove(nextTask);
    DisplayResults(feed);
}

É possível examinar esta versão do programa na seção Criando o aplicativo concluído no final do tópico. Ou você pode acompanhar as instruções em Baixando o aplicativo finalizado para baixar o projeto.

Aviso

O uso de WhenAny em um loop, conforme descrito no exemplo, não gera problemas que envolvam um pequeno número de tarefas.No entanto, outras abordagens são mais eficientes se você tem um grande número de tarefas para processar.Para obter mais informações e exemplos, consulte Processando tarefas à medida que são concluídas.

Baixando o código de iniciantes

É possível baixar o código inicial para o exemplo de Exemplo de Async: Ponte do .NET com o Windows. Se você não tiver acesso à Internet, siga as instruções em Compilando o código inicial no final deste tópico para criar o código inicial.

Após o download do código, você abre e executa-o realizando as seguintes etapas.

  1. Descompacte o arquivo que você baixou e inicie o Visual Studio 2012.

  2. Na barra de menu, escolha Arquivo, Abrir, Projeto/solução.

  3. Navegue até a pasta que contém o código de exemplo descompactado, e abra o arquivo de solução (.sln) para AsTaskWhenAnyDemoVB ou AsTaskWhenAnyDemoCS.

  4. Em Gerenciador de Soluções, abra o menu de atalho para o projeto SequentialBlogReader e escolha Definir como Projeto de Inicialização.

  5. Escolha a tecla F5 para compilar e executar o projeto.

  6. Execute o código várias vezes para verificar se os resultados aparecem na mesma ordem em cada vez.

É possível examinar o arquivo MainPage.xaml.vb ou MainPage.xaml.cs na seção Criando o código inicial no final do tópico.

O exemplo se baseia no leitor do blog que é descrito em Início rápido: usando o operador await para a programação assíncrona. No entanto, o código para iniciantes desse tópico baixa vários feeds do blog em vez de apenas um.

Para obter informações sobre uma ampla variedade de aperfeiçoamentos e de extensões que você pode fazer no aplicativo, consulte Criar um leitor de blog.

Baixando o aplicativo concluído

Se você não desejar compilar o próprio exemplo, poderá baixar o exemplo completo. Siga as instruções na seção Baixando o código para iniciantes, mas escolha WhenAnyBlogReader como o Projeto de inicialização.

Execute o programa várias vezes para verificar se os feeds do blog aparecem em ordens diferentes.

É possível examinar o arquivo MainPage.xaml.vb ou MainPage.xaml.cs na seção Criando o aplicativo concluído no final do tópico.

Compilando o código para iniciantes

É possível baixar os exemplos deste tópico em Exemplo de Async: Ponte do .NET com o Windows. Se você preferir configurar o aplicativo por conta própria, siga estas etapas.

  1. Inicie o Visual Studio 2012.

  2. Na barra de menu, escolha Arquivo, Novo, Projeto.

    A Caixa de diálogo Novo Projeto é exibida.

  3. Na categoria Instalado, Modelos, escolha Visual Basic ou Visual C#, e então escolha Windows Store na lista de tipos de projetos.

  4. Na lista de tipos de projeto, selecione Aplicativo em Branco (XAML).

  5. Nomeie o projeto SequentialBlogReader e escolha o botão OK.

    O novo projeto aparece no Gerenciador de Soluções.

  6. Em Gerenciador de Soluções, abra o menu de atalho para MainPage.xaml e escolha Abrir.

  7. Na janela XAML de MainPage.xaml, substitua o código pelo seguinte.

    <Page
        x:Class="SequentialBlogReader.MainPage"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:AsTaskWhenAnyDemo"
        xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Stretch" Margin="325,128,330,0" VerticalAlignment="Top" Click="StartButton_Click" Height="71" Background="#FFA89B9B" FontWeight="Bold" FontSize="36"/>
            <TextBox x:Name="ResultsTextBox" Margin="325,222,330,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="546" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" />
        </Grid>
    </Page>
    

    Uma janela simples que contém uma caixa de texto e um botão aparece na janela Design de MainPage.xaml.

    Para obter informações sobre uma ampla variedade de aperfeiçoamentos e de extensões que você pode fazer na interface de usuário, consulte Criar um leitor de blog.

  8. Em Gerenciador de Soluções, abra o menu de atalho para MainPage.xaml.vb ou MainPage.xaml.cs e, em seguida, escolha Exibir Código.

  9. Substitua o código em MainPage.xaml.vb ou em MainPage.xaml.cs pelo código a seguir.

    ' Add an Imports statement for SyndicationClient. 
    Imports Windows.Web.Syndication
    
    
    ' The Blank Page item template is documented at http:'go.microsoft.com/fwlink/?LinkId=234238 
    
    Public NotInheritable Class MainPage
        Inherits Page
    
        Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    
        End Sub 
    
    
        ' The async modifier enables you to use await in the event handler. 
        Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
            ResultsTextBox.Text = "" 
    
            ' Disable the button until the operation is complete.
            StartButton.IsEnabled = False 
    
            Dim client As Windows.Web.Syndication.SyndicationClient = New SyndicationClient()
    
            ' Force the SyndicationClient to download the information.
            client.BypassCacheOnRetrieve = True 
    
            Dim uriList = CreateUriList()
    
            Try 
                Dim feedsQuery As IEnumerable(Of IAsyncOperationWithProgress(Of SyndicationFeed, 
                                                                                RetrievalProgress)) =
                                                                From uri In uriList
                                                                Select client.RetrieveFeedAsync(uri)
    
                ' Run the query to start all the asynchronous processes. 
                Dim blogFeedOpsList As List(Of IAsyncOperationWithProgress(Of SyndicationFeed, 
                                                                           RetrievalProgress)) =
                                                               feedsQuery.ToList()
    
                Dim feed As SyndicationFeed
                For Each blogFeedOp In blogFeedOpsList
                    ' The Await operator retrieves the final result (a SyndicationFeed instance) 
                    ' from each IAsyncOperation instance.
                    feed = Await blogFeedOp
                    DisplayResults(feed)
                Next 
    
            Catch ex As Exception
                ResultsTextBox.Text =
                    "Page could not be loaded." & vbCrLf & "Exception: " & ex.ToString()
            End Try 
    
            ' Reenable the button in case you want to run the operation again.
            StartButton.IsEnabled = True 
        End Sub 
    
    
        Function CreateUriList() As List(Of Uri)
    
            ' Create a list of URIs. 
            Dim uriList = New List(Of Uri) From
            {
                    New Uri("https://windowsteamblog.com/windows/b/developers/atom.aspx"),
                    New Uri("https://windowsteamblog.com/windows/b/extremewindows/atom.aspx"),
                    New Uri("https://windowsteamblog.com/windows/b/bloggingwindows/atom.aspx"),
                    New Uri("https://windowsteamblog.com/windows/b/springboard/atom.aspx")
            }
            Return uriList
        End Function 
    
    
        Sub DisplayResults(sf As SyndicationFeed)
    
            ' Title of the blog.
            ResultsTextBox.Text &= sf.Title.Text & vbCrLf
    
            ' Titles and dates for blog posts. 
            For Each item As SyndicationItem In sf.Items
    
                ResultsTextBox.Text &= vbTab & item.Title.Text & ", " &
                                    item.PublishedDate.ToString() & vbCrLf
            Next
    
            ResultsTextBox.Text &= vbCrLf
        End Sub 
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    
    // Add a using directive for SyndicationClient. 
    using Windows.Web.Syndication;
    
    
    namespace SequentialBlogReader
    {
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }
    
    
            private async void StartButton_Click(object sender, RoutedEventArgs e)
            {
                ResultsTextBox.Text = "";
    
                // Disable the button until the operation is complete.
                StartButton.IsEnabled = false;
    
                Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();
    
                // Force the SyndicationClient to download the information.
                client.BypassCacheOnRetrieve = true;
    
                var uriList = CreateUriList();
    
                try
                {
                    IEnumerable<IAsyncOperationWithProgress<SyndicationFeed, 
                        RetrievalProgress>> feedsQuery = from uri in uriList
                                                         select client.RetrieveFeedAsync(uri);
    
                    // Run the query to start all the asynchronous processes.
                    List<IAsyncOperationWithProgress<SyndicationFeed, 
                        RetrievalProgress>> blogFeedOpsList = feedsQuery.ToList();
    
                    SyndicationFeed feed;
                    foreach (var blogFeedOp in blogFeedOpsList)
                    {
                        // The await operator retrieves the final result (a SyndicationFeed instance) 
                        // from each IAsyncOperation instance.
                        feed = await blogFeedOp;
                        DisplayResults(feed);
                    }
                }
                catch (Exception ex)
                {
                    ResultsTextBox.Text =
                        "Page could not be loaded.\n\r" + "Exception: " + ex.ToString();
                }
    
                // Reenable the button in case you want to run the operation again.
                StartButton.IsEnabled = true;
            }
    
            List<Uri> CreateUriList()
            {
                // Create a list of URIs.
                List<Uri> uriList = new List<Uri> 
                { 
                    new Uri("https://windowsteamblog.com/windows/b/developers/atom.aspx"),
                    new Uri("https://windowsteamblog.com/windows/b/extremewindows/atom.aspx"),
                    new Uri("https://windowsteamblog.com/windows/b/bloggingwindows/atom.aspx"),
                    new Uri("https://windowsteamblog.com/windows/b/springboard/atom.aspx")
                };
                return uriList;
            }
    
    
            void DisplayResults(SyndicationFeed sf)
            {
                // Title of the blog.
                ResultsTextBox.Text += sf.Title.Text + "\r\n";
    
                // Titles and dates for blog posts. 
                foreach (SyndicationItem item in sf.Items)
                {
                    ResultsTextBox.Text += "\t" + item.Title.Text + ", " +
                                        item.PublishedDate.ToString() + "\r\n";
                }
                ResultsTextBox.Text += "\r\n";
            }
        }
    }
    
  10. Escolha a tecla F5 para executar o programa e escolha o botão Iniciar.

Compilando o aplicativo concluído

É possível baixar os exemplos deste tópico em Exemplo de Async: Ponte do .NET com o Windows. Se você preferir configurar o aplicativo por conta própria, siga estas etapas.

  1. Inicie o Visual Studio 2012.

  2. Na barra de menu, escolha Arquivo, Novo, Projeto.

    A Caixa de diálogo Novo Projeto é exibida.

  3. Na categoria Instalado, Modelos, escolha Visual Basic ou Visual C#, e então escolha Windows Store.

  4. Na lista de tipos de projeto, escolha Aplicativo em Branco (XAML).

  5. Nomeie o projeto WhenAnyBlogReader e escolha o botão OK.

    O novo projeto aparece no Gerenciador de Soluções.

  6. Em Gerenciador de Soluções, abra o menu de atalho para MainPage.xaml e escolha Abrir.

  7. Na janela XAML de MainPage.xaml, substitua o código pelo seguinte.

    <Page
        x:Class="WhenAnyBlogReader.MainPage"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:AsTaskWhenAnyDemo"
        xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Stretch" Margin="325,128,330,0" VerticalAlignment="Top" Click="StartButton_Click" Height="71" Background="#FFA89B9B" FontWeight="Bold" FontSize="36"/>
            <TextBox x:Name="ResultsTextBox" Margin="325,222,330,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="546" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" />
        </Grid>
    </Page>
    

    Uma janela simples que contém uma caixa de texto e um botão aparece na janela Design de MainPage.xaml.

    Para obter informações sobre uma ampla variedade de aperfeiçoamentos e de extensões que você pode fazer no aplicativo, consulte Criar um leitor de blog.

  8. Em Gerenciador de Soluções, abra o menu de atalho para MainPage.xaml.vb ou MainPage.xaml.cs e, em seguida, escolha Exibir Código.

  9. Substitua o código em MainPage.xaml.vb ou em MainPage.xaml.cs pelo código a seguir.

    ' Add an Imports statement for SyndicationClient. 
    Imports Windows.Web.Syndication
    
    ' Add an Imports statement for the Tasks. 
    Imports System.Threading.Tasks
    
    ' The Blank Page item template is documented at http:'go.microsoft.com/fwlink/?LinkId=234238 
    
    Public NotInheritable Class MainPage
        Inherits Page
    
        Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
        End Sub 
    
    
        Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
    
            ResultsTextBox.Text = "" 
    
            ' Disable the button until the operation is complete.
            StartButton.IsEnabled = False 
    
            Dim client As Windows.Web.Syndication.SyndicationClient = New SyndicationClient()
    
            ' Force the SyndicationClient to download the information.
            client.BypassCacheOnRetrieve = True 
    
            Dim uriList = CreateUriList()
    
            ' The following code avoids the use of implicit typing so that you  
            ' can see the types clearly. 
    
            Try 
                Dim feedsQuery As IEnumerable(Of Task(Of SyndicationFeed)) =
                    From uri In uriList
                    Select client.RetrieveFeedAsync(uri).AsTask()
                ' AsTask changes the returns from RetrieveFeedAsync into tasks. 
    
                ' Run the query to start all the asynchronous processes. 
                Dim blogFeedTasksList As List(Of Task(Of SyndicationFeed)) = feedsQuery.ToList()
    
                Dim feed As SyndicationFeed
    
                ' Repeat the following until there are no tasks left: 
                '    - Grab the first one that finishes. 
                '    - Retrieve the results from the task (what the return statement  
                '      in RetrieveFeedAsync returns). 
                '    - Remove the task from the list. 
                '    - Display the results. 
                While blogFeedTasksList.Count > 0
                    Dim nextTask As Task(Of SyndicationFeed) = Await Task.WhenAny(blogFeedTasksList)
                    feed = Await nextTask
                    blogFeedTasksList.Remove(nextTask)
                    DisplayResults(feed)
                End While 
    
            Catch ex As Exception
                ResultsTextBox.Text =
                    "Page could not be loaded." & vbCrLf & "Exception: " & ex.ToString()
            End Try 
    
            ' Reenable the button in case you want to run the operation again.
            StartButton.IsEnabled = True 
        End Sub 
    
    
        Function CreateUriList() As List(Of Uri)
    
            ' Create a list of URIs. 
            Dim uriList = New List(Of Uri) From
            {
                    New Uri("https://windowsteamblog.com/windows/b/developers/atom.aspx"),
                    New Uri("https://windowsteamblog.com/windows/b/extremewindows/atom.aspx"),
                    New Uri("https://windowsteamblog.com/windows/b/bloggingwindows/atom.aspx"),
                    New Uri("https://windowsteamblog.com/windows/b/springboard/atom.aspx")
            }
            Return uriList
        End Function 
    
    
        Sub DisplayResults(sf As SyndicationFeed)
    
            ' Title of the blog.
            ResultsTextBox.Text &= sf.Title.Text & vbCrLf
    
            ' Titles and dates for blog posts. 
            For Each item As SyndicationItem In sf.Items
    
                ResultsTextBox.Text &= vbTab & item.Title.Text & ", " &
                                    item.PublishedDate.ToString() & vbCrLf
            Next
    
            ResultsTextBox.Text &= vbCrLf
        End Sub 
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using Windows.Foundation;
    using Windows.Foundation.Collections;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Input;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Navigation;
    
    // Add a using directive for SyndicationClient. 
    using Windows.Web.Syndication;
    
    // Add a using directive for the Tasks. 
    using System.Threading.Tasks;
    
    
    namespace WhenAnyBlogReader
    {
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }
    
    
            private async void StartButton_Click(object sender, RoutedEventArgs e)
            {
                ResultsTextBox.Text = "";
    
                // Disable the button until the operation is complete.
                StartButton.IsEnabled = false;
    
                Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();
    
                // Force the SyndicationClient to download the information.
                client.BypassCacheOnRetrieve = true;
    
                var uriList = CreateUriList();
    
                // The following code avoids the use of implicit typing (var) so that you  
                // can identify the types clearly. 
    
                try
                {
                    IEnumerable<Task<SyndicationFeed>> feedsQuery =
                            from uri in uriList
                            // AsTask changes the returns from RetrieveFeedAsync into tasks. 
                            select client.RetrieveFeedAsync(uri).AsTask();
    
                    // Run the query to start all the asynchronous processes.
                    List<Task<SyndicationFeed>> blogFeedTasksList = feedsQuery.ToList();
    
                    SyndicationFeed feed;
    
                    // Repeat the following until no tasks remain: 
                    //    - Grab the first one that finishes. 
                    //    - Retrieve the results from the task (what the return statement  
                    //      in RetrieveFeedAsync returns). 
                    //    - Remove the task from the list. 
                    //    - Display the results. 
                    while (blogFeedTasksList.Count > 0)
                    {
                        Task<SyndicationFeed> nextTask = await Task.WhenAny(blogFeedTasksList);
                        feed = await nextTask;                    
                        blogFeedTasksList.Remove(nextTask);
                        DisplayResults(feed);
                    }
                }
                catch (Exception ex)
                {
                    ResultsTextBox.Text =
                        "Page could not be loaded.\n\r" + "Exception: " + ex.ToString();
                }
    
                // Reenable the button in case you want to run the operation again.
                StartButton.IsEnabled = true;
            }
    
    
            List<Uri> CreateUriList()
            {
                // Create a list of URIs.
                List<Uri> uriList = new List<Uri> 
                { 
                    new Uri("https://windowsteamblog.com/windows/b/developers/atom.aspx"),
                    new Uri("https://windowsteamblog.com/windows/b/extremewindows/atom.aspx"),
                    new Uri("https://windowsteamblog.com/windows/b/bloggingwindows/atom.aspx"),
                    new Uri("https://windowsteamblog.com/windows/b/springboard/atom.aspx")
                };
                return uriList;
            }
    
    
            void DisplayResults(SyndicationFeed sf)
            {
                // Title of the blog.
                ResultsTextBox.Text += sf.Title.Text + "\r\n";
    
                // Titles and dates for blog posts. 
                foreach (SyndicationItem item in sf.Items)
                {
                    ResultsTextBox.Text += "\t" + item.Title.Text + ", " +
                                        item.PublishedDate.ToString() + "\r\n";
                }
                ResultsTextBox.Text += "\r\n";
            }
        }
    }
    
  10. Escolha a tecla F5 para executar o programa e escolha o botão Iniciar.

Consulte também

Referência

AsTask``1

WhenAny``1

Conceitos

Programação assíncrona com Async e Await (C# e Visual Basic)

Cancelar as demais tarefas assíncronas depois que uma delas estiver concluída (C# e Visual Basic)

Iniciar várias tarefas assíncronas e processá-las na conclusão (C# e Visual Basic)

Outros recursos

Início Rápido: usando o operador await para programação assíncrona

Crie um leitor do blog

IAsyncOperationWithProgress