WhenAny: Puente entre .NET Framework y Windows en tiempo de ejecución (C# y Visual Basic)

El ejemplo de este tema combina un tipo Windows en tiempo de ejecución que descarga blogs de forma asincrónica con un método de .NET Framework que procesa tareas asincrónicas en el orden en que se completan. Para obtener más información acerca del tipo, vea SyndicationClient. Para obtener más información sobre el método, vea Task.WhenAny..

Combinando estas características, puede empezar a descargar varias fuentes de blog simultáneamente y procesar los resultados como finalizados. Si una fuente descarga más rápidamente que otras, los resultados aparecen primero. Al utilizar un método SyndicationClient, puede descargar las fuentes de forma más sencilla; utilizando el método Task.WhenAny, le resultará más fácil identificar la siguiente fuente que ha finalizado la descarga.

Nota

Para ejecutar el ejemplo, debe tener Windows 8 instalado en el equipo.Además, si desea ejecutar el ejemplo desde Visual Studio, también debe tener instalados Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 para Windows 8 o Visual Studio Express 2013 para Windows.

El código siguiente combina estas características de Windows en tiempo de ejecución y de .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();
}

En el ejemplo se generan resultados similares a los de las siguientes líneas. Para cada blog, la pantalla muestra el título del blog seguido de los títulos y fechas de las entradas de 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

El resto de este tema se proporciona detalles sobre cómo crear el ejemplo y cómo funciona.

Debe tener Visual Studio 2012 y Windows 8 instalado en el equipo para poder ejecutar esta aplicación.

Este tema contiene las secciones siguientes.

  • Opciones de configuración del ejemplo
  • Descripción del código de inicio
  • Extender el código de inicio
  • Descargar el código de inicio
  • Descargar la aplicación finalizada
  • Compilar el código de inicio
  • Compilar la aplicación finalizada
  • Temas relacionados

Opciones de configuración del ejemplo

El ejemplo se basa en el lector de blog que se describe en Inicio rápido: llamadas a API asincrónicas en C# o Visual Basic. Sin embargo, el código de inicio de este tema descarga varias fuentes de blog en lugar de solo una.

El código de inicio utiliza la funcionalidad Windows en tiempo de ejecución para descargar blogs secuencialmente. Es decir, los blogs se descargan en el orden en que se muestran en una colección de direcciones URL. La aplicación finalizada agrega funcionalidad a partir de .NET Framework para descargar blogs en el orden en que se completan.

Puede configurar el código de ejemplo de cualquiera de las maneras siguientes:

  • Código de inicio.

    • Puede descargar el código de inicio siguiendo las instrucciones de Descargar el código de inicio.

    • Puede crear el código de inicio personalmente siguiendo las instrucciones de Compilar el código de inicio.

    • Puede revisar el código inicial sin tener que implementarlo desplazándose a Compilar el código de inicio.

  • Aplicación finalizada.

    • Puede descargar la aplicación acabada siguiendo las instrucciones de Descargar la aplicación finalizada

    • Puede compilar la aplicación usted mismo siguiendo las instrucciones de Compilar la aplicación finalizada.

    • Puede revisar la aplicación finalizada sin tener que implementarla desplazándose a Compilar la aplicación finalizada.

La sección Descripción del código de inicio describe los puntos clave de la solución básica.

En la sección Extender el código de inicio se muestra cómo modificar el código agregando AsTask``2 y Task.WhenAny.

Descripción del código de inicio

El código de inicio utiliza un método SyndicationClient, SyndicationClient.RetrieveFeedAsync | retrieveFeedAsync para descargar una fuente de blog de cada URI en una lista de URI. Cada llamada al método devuelve una instancia de IAsyncOperationWithProgress que representa una operación asincrónica en curso. Cuando es awaited, la operación asincrónica genera una clase SyndicationFeed que contiene información sobre la fuente de blog descargada.

El código define una consulta que aplique RetrieveFeedAsync a cada entrada en una lista de URI. Cuando se ejecuta, la consulta devuelve una colección de instancias 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 ejecuta la consulta e inicia los procesos asincrónicos, como muestra el código siguiente.

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

En este punto, tiene una lista de instancias activas IAsyncOperationWithProgress. Todavía debe esperar hasta que cada instancia obtenga los resultados finales.

El bucle siguiente espera cada instancia IAsyncOperationWithProgress para recuperar los resultados 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);
}

Puede revisar esta versión del programa en la sección Compilar el código de inicio al final del tema.

Puede encontrar más información acerca de la programación con las API asincrónicas de Windows en tiempo de ejecución en Inicio rápido: llamadas a API asincrónicas en C# o Visual Basic.

Extender el código de inicio

El código de inicio muestra que SyndicationClient facilita la descarga de blogs. El paso restante para completar el ejemplo es habilitar la aplicación para procesar blogs en el orden en que las descargas se completan en lugar del orden en que aparecen en la lista de URI.

La clave para lograr el aumento es el método Task.WhenAny . Cuando se aplica WhenAny a una colección de procesos asincrónicos, el método devuelve el primer proceso que completa, reduciendo el tiempo que se debe esperar. En este ejemplo, el orden en el que la información de la fuente de blog aparece no es importante. Si una descarga es lenta, los resultados de otro blog pueden mostrarse primero. La situación es perfecta para WhenAny salvo una acción: WhenAny requiere una colección de tareas.

Invocar AsTask

WhenAny requiere una colección Task o instancias Task, pero el método SyndicationClient que descarga el blog devuelve una instancia IAsyncOperationWithProgress. Por tanto, la aplicación debe funcionar como un puente entre los objetos IAsyncOperationWithProgress de Windows en tiempo de ejecución y los objetos Task de .NET Framework.

.NET Framework proporciona métodos de extensión de AsTask``2 para crear la transición. Cuando se invoca AsTask en una instancia de IAsyncOperationWithProgress, AsTask devuelve una tarea que representa la operación asincrónica. La tarea se completa cuando se completa la instancia correspondiente de IAsyncOperationWithProgress y la tarea tiene el resultado o excepción de la instancia.

Por consiguiente, únicamente se invoca AsTask en cada instancia de IAsyncOperationWithProgress que RetrieveFeedAsync devuelve, como muestra el código siguiente. El código cambia el nombre de las variables para reflejar el cambio a tareas y utiliza escritura explícita para mayor claridad.

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();

Nota

Probablemente no sabe que AsTask desempeña un rol importante en la programación asincrónica.El compilador utiliza AsTask siempre que aplique un operador await a una instancia de IAsyncAction o de IAsyncOperation, como muestra el código siguiente.

Aplicar WhenAny

El último paso en la conversión es agregar el método Task.WhenAny a la aplicación. WhenAny se aplica a una colección de tareas (blogFeedTasksList) y devuelve la primera tarea a la colección que completa. Más específicamente, WhenAny devuelve una tarea que, cuando se espera, se evalúa a la tarea que finalizó primero.

La instrucción siguiente llama a WhenAny y espera el resultado. El código utiliza un tipo explícito para mostrar el resultado más claramente.

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

El código siguiente hace lo mismo que la instrucción anterior pero interrumpe la operación en dos instrucciones para aclarar lo que ocurre. La primera instrucción llama a WhenAny y la segunda instrucción espera el 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 último, debe esperar nextTask para recuperar los resultados (una instancia de SyndicationFeed) de la tarea que finalizó primero y, a continuación, debe quitar nextTask de la lista de modo que no la procese de nuevo.

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

Utilice un bucle while para realizar estos pasos para cada tarea en 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);
}

Puede revisar esta versión del programa en la sección Compilar la aplicación finalizada al final del tema. O puede seguir las instrucciones de Descargar la aplicación finalizada para descargar el proyecto.

Advertencia

El uso de WhenAny en un bucle, como se describe en el ejemplo, está bien para los problemas que implican una pequeña cantidad de tareas.Sin embargo, otros enfoques son más eficientes si tiene un gran número de tareas para procesar.Para obtener más información y ejemplos, vea Tareas de procesamiento como completa.

Descargar el código de inicio

Puede descargar el código de inicio para el ejemplo de Ejemplo de Async: Puente de .NET en Windows. Si no tiene acceso a Internet, siga las instrucciones de Compilar el código de inicio al final de este tema para crear el código de inicio.

Después de descargar el código, ábralo y ejecútelo siguiendo estos pasos.

  1. Descomprima el archivo que ha descargado y, a continuación, inicie Visual Studio 2012.

  2. En la barra de menú, elija Archivo, Abrir, Proyecto/Solución.

  3. Navegue a la carpeta que contiene el código de ejemplo descomprimido y abra el archivo de solución (.sln) para AsTaskWhenAnyDemoVB o AsTaskWhenAnyDemoCS.

  4. En el Explorador de soluciones, abra el acceso directo del proyecto SequentialBlogReader y, a continuación, elija Establecer como proyecto de inicio.

  5. Elija la tecla F5 para compilar y ejecutar el proyecto.

  6. Ejecute el código varias veces para comprobar que los resultados aparecen en el mismo orden cada vez.

Puede revisar el archivo MainPage.xaml.vb o MainPage.xaml.cs en la sección Compilar el código de inicio al final del tema.

El ejemplo se basa en el lector de blog que se describe en Inicio rápido: llamadas a API asincrónicas en C# o Visual Basic. Sin embargo, el código de inicio de este tema descarga varias fuentes de blog en lugar de solo una.

Para obtener información sobre una gran variedad de mejoras y de extensiones que puede implementar en la aplicación, vea Cree un lector de blogs.

Descargar la aplicación finalizada

Si no desea compilar el ejemplo personalmente, puede descargar el ejemplo completo. Siga las instrucciones de la sección Descargar el código de inicio, pero elija WhenAnyBlogReader como Proyecto de inicio.

Ejecute el programa varias veces para comprobar que los blogs aparecen en un orden diferente.

Puede revisar el archivo MainPage.xaml.vb o MainPage.xaml.cs en la sección Compilar la aplicación finalizada al final del tema.

Compilar el código de inicio

Puede descargar los ejemplos de este tema de Ejemplo de Async: Puente de .NET en Windows. Si prefiere establecer la aplicación sobre sí mismo, siga estos pasos.

  1. Inicie Visual Studio 2012.

  2. En la barra de menús, elija Archivo, Nuevo, Proyecto.

    Aparece el cuadro de diálogo Nuevo proyecto.

  3. En la categoría Instaladas, Plantillas, elija Visual Basic o Visual C# y, a continuación, elija Tienda Windows en la lista de tipos de proyecto.

  4. En la lista de tipos de proyecto, elija Aplicación vacía (XAML).

  5. Denomine SequentialBlogReader al proyecto y, a continuación, elija el botón Aceptar.

    El nuevo proyecto aparecerá en el Explorador de soluciones.

  6. En el Explorador de soluciones, abra el menú contextual para MainPage.xaml y, a continuación, elija Abrir.

  7. En la ventana XAML de MainPage.xaml, reemplace el código por el código siguiente.

    <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>
    

    Una sencilla ventana que contiene un cuadro de texto y un botón aparece en la ventana Diseño de MainPage.xaml.

    Para obtener información sobre una gran variedad de mejoras y de extensiones que puede implementar en la interfaz de usuario, vea Cree un lector de blogs.

  8. En el Explorador de soluciones, abra el menú contextual de MainPage.xaml.vb o MainPage.xaml.cs y, a continuación, elija Código de la vista.

  9. Reemplace el código de MainPage.xaml.vb o MainPage.xaml.cs por el código siguiente.

    ' 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. Elija la tecla F5 para ejecutar el programa y, a continuación, el botón Iniciar.

Compilar la aplicación finalizada

Puede descargar los ejemplos de este tema de Ejemplo de Async: Puente de .NET en Windows. Si prefiere establecer la aplicación sobre sí mismo, siga estos pasos.

  1. Inicie Visual Studio 2012.

  2. En la barra de menús, elija Archivo, Nuevo, Proyecto.

    Aparece el cuadro de diálogo Nuevo proyecto.

  3. En Instalado, categoría de Plantillas, elija Visual Basic o Visual C# y, a continuación, elija Tienda Windows.

  4. En la lista de tipos de proyecto, elija Aplicación vacía (XAML).

  5. Denomine WhenAnyBlogReader al proyecto y, a continuación, elija el botón Aceptar.

    El nuevo proyecto aparecerá en el Explorador de soluciones.

  6. En el Explorador de soluciones, abra el menú contextual para MainPage.xaml y, a continuación, elija Abrir.

  7. En la ventana XAML de MainPage.xaml, reemplace el código por el código siguiente.

    <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>
    

    Una sencilla ventana que contiene un cuadro de texto y un botón aparece en la ventana Diseño de MainPage.xaml.

    Para obtener información sobre una gran variedad de mejoras y de extensiones que puede implementar en la aplicación, vea Cree un lector de blogs.

  8. En el Explorador de soluciones, abra el menú contextual de MainPage.xaml.vb o MainPage.xaml.cs y, a continuación, elija Código de la vista.

  9. Reemplace el código de MainPage.xaml.vb o MainPage.xaml.cs por el código siguiente.

    ' 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. Elija la tecla F5 para ejecutar el programa y, a continuación, el botón Iniciar.

Vea también

Referencia

WhenAny``1

AsTask``1

Conceptos

Programación asincrónica con Async y Await (C# y Visual Basic)

Cancelar las tareas asincrónicas restantes cuando se completa una (C# y Visual Basic)

Iniciar varias tareas asincrónicas y procesarlas a medida que se completan (C# y Visual Basic)

Otros recursos

Inicio rápido: llamadas a API asincrónicas en C# o Visual Basic

Crear un lector de blogs

IAsyncOperationWithProgress