WhenAny : combler l'écart entre .NET Framework et Windows Runtime (C# et Visual Basic)

L'exemple de cette rubrique combine un type Windows Runtime qui télécharge des publications de blog de façon asynchrone avec une méthode du .NET Framework qui traite les tâches asynchrones dans l'ordre de leur exécution. Pour plus d'informations sur le type, consultez SyndicationClient. Pour plus d'informations sur la méthode, consultez Task.WhenAny.

En combinant ces fonctionnalités, vous pouvez commencer à télécharger plusieurs publications de blog simultanément et à traiter les résultats lorsque les téléchargements se terminent. Si un flux est téléchargé plus rapidement que les autres, ses résultats apparaissent en premier. En utilisant une méthode SyndicationClient, vous pouvez télécharger plus facilement les flux. En utilisant la méthode Task.WhenAny, vous pouvez identifier plus facilement le flux suivant dont le téléchargement est terminé.

Notes

Pour exécuter l'exemple, Windows 8 doit être installé sur votre ordinateur.En outre, si vous souhaitez exécuter l'exemple dans Visual Studio, vous devez avoir aussi installé Visual Studio 2012, Visual Studio 2013Visual Studio Express 2012 pour Windows 8 ou Visual Studio Express 2013 pour Windows.

Le code suivant combine ces fonctionnalités à partir de Windows Runtime et du .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();
}

L'exemple génère une sortie qui ressemble aux lignes suivantes. Pour chaque blog, l'affichage indique le titre du blog, suivi des titres et des dates des publications 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

Le reste de cette rubrique fournit des détails sur la création de l'exemple et sur son fonctionnement.

Vous devez avoir installé Visual Studio 2012 et Windows 8 sur votre ordinateur pour exécuter cette application.

Cette rubrique comprend les sections suivantes.

  • Options d'installation de l'exemple
  • Fonctionnement du code de démarrage
  • Extension du code de démarrage
  • Téléchargement du code de démarrage
  • Téléchargement de l'application terminée
  • Génération du code de démarrage
  • Génération de l'application terminée
  • Rubriques connexes

Options d'installation de l'exemple

L'exemple repose sur le lecteur de blog décrit dans Démarrage rapide : appel d'API asynchrones en C# ou Visual Basic. Toutefois, le code de démarrage pour cette rubrique télécharge plusieurs publications de blog au lieu d'une seule.

Le code de démarrage utilise la fonctionnalité Windows Runtime pour télécharger séquentiellement les publications de blog. En d'autres termes, les publications de blog sont téléchargées dans l'ordre dans lequel elles sont répertoriées dans une collection d'URL. L'application terminée ajoute des fonctionnalités à partir du .NET Framework pour permettre le téléchargement des publications de blog dans l'ordre de leur exécution.

Vous pouvez installer le code de l'exemple de l'une des façons suivantes :

  • Code de démarrage.

    • Vous pouvez télécharger le code de démarrage en suivant les instructions de Téléchargement du code de démarrage,

    • Vous pouvez créer le code de démarrage vous-même en suivant les instructions de Génération du code de démarrage.

    • Vous pouvez examiner le code de démarrage sans l'implémenter en défilant jusqu'à Génération du code de démarrage.

  • Application terminé.

    • Vous pouvez télécharger l'application finie en suivant les instructions de Téléchargement d'applications finies

    • Vous pouvez générer l'application vous-même en suivant les instructions de Génération d'applications finies.

    • Vous pouvez examiner l'application finie sans l'implémenter en défilant jusqu'à Génération d'applications finies.

La section Fonctionnement du code de démarrage traite des points clés de la solution de base.

La section Extension du code de démarrage indique comment modifier le code en ajoutant AsTask``2 et Task.WhenAny.

Fonctionnement du code de démarrage

Le code de démarrage utilise une méthode, SyndicationClientRetrieveFeedAsync, pour télécharger une publication de blog à partir de chaque URI d'une liste d'URI. Chaque appel de la méthode retourne une instance IAsyncOperationWithProgress qui représente une opération asynchrone en cours. Une fois attendue, l'opération asynchrone produit une instance SyndicationFeed qui contient les informations sur le billet de blog téléchargé.

Le code définit une requête qui applique RetrieveFeedAsync à chaque entrée d'une liste d'URI. Lors de son exécution, la requête retourne une collection d'instances 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 exécute la requête et démarre les processus asynchrones, comme le montre le code suivant.

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

À ce stade, vous avez une liste d'instances IAsyncOperationWithProgress actives. Vous devez encore attendre chaque instance pour obtenir les résultats finaux.

La boucle suivante attend chaque instance de IAsyncOperationWithProgress pour récupérer les résultats 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);
}

Vous pouvez étendre cette version du programme dans la section Génération du code de démarrage à la fin de la rubrique.

Vous trouverez plus d'informations sur la programmation avec les API Windows Runtime asynchrones dans Démarrage rapide : utilisation de l'opérateur await pour la programmation asynchrone.

Extension du code de démarrage

Le code de démarrage montre que SyndicationClient facilite le téléchargement des publications de blog. La dernière étape pour terminer l'exemple est de permettre à l'application de traiter les publications de blog selon l'ordre d'achèvement des téléchargements, et non selon leur ordre d'apparition dans la liste des URI.

La clé de l'amélioration réside dans la méthode Task.WhenAny. Lorsque vous appliquez WhenAny à une collection de processus asynchrones, la méthode retourne le premier processus qui se termine, réduisant ainsi le temps d'attente. Dans cet exemple, l'ordre dans lequel les informations de flux des blogs apparaissent n'est pas important. Si un téléchargement est lent, les résultats d'un autre blog peuvent s'afficher en premier. La situation semble transparente pour WhenAny, à un détail près : WhenAny requiert une collection de tâches.

Appel d'AsTask

WhenAny requiert une collection d'instances Task ou Task, mais la méthode SyndicationClient qui télécharge les billets de blog retourne une instance IAsyncOperationWithProgress. Par conséquent, l'application doit établir une passerelle entre les objets IAsyncOperationWithProgress du Windows Runtime et les objets Task du .NET Framework.

Le .NET Framework fournit des méthodes d'extension AsTask``2 pour effectuer la transition. Lorsque vous appelez AsTask sur une instance d'IAsyncOperationWithProgress, AsTask retourne une tâche qui représente l'opération asynchrone. La tâche se termine lorsque l'instance IAsyncOperationWithProgress est terminée, et que la tâche a le résultat ou l'exception de l'instance.

Par conséquent, vous appelez simplement AsTask sur chaque instance IAsyncOperationWithProgress que retourne d'RetrieveFeedAsync, comme l'illustre le code ci-après. Le code renomme les variables pour refléter la modification des tâches et utilise un typage explicite à des fins de clarté.

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

Notes

AsTask joue un rôle important dans la programmation asynchrone et vous n'en avez probablement pas conscience.Le compilateur utilise AsTask chaque fois que vous appliquez un opérateur await à une instance de IAsyncAction ou de IAsyncOperation, comme le montre le code suivant.

Appliquer WhenAny

La dernière étape de la conversion consiste à ajouter la méthode Task.WhenAny à l'application. WhenAny s'applique à une collection de tâches (blogFeedTasksList) et retourne la première tâche de la collection qui se termine. Plus spécifiquement, WhenAny retourne une tâche qui, lorsqu'elle est attendue, prend la valeur de la tâche qui s'est terminée la première.

L'instruction suivante appelle WhenAny et attend le résultat. Le code utilise le typage explicite pour afficher le résultat plus clairement.

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

Le code suivant fait la même chose que l'instruction précédente mais scinde l'opération en deux instructions pour clarifier ce qui se produit. La première instruction appelle WhenAny, et la seconde instruction attend le résultat.

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

Enfin, vous devez attendre nextTask pour récupérer les résultats (une instance SyndicationFeed ) de la tâche qui a terminé en premier, puis vous devez supprimer le nextTask de la liste pour ne pas le traiter à nouveau.

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

Utilisez une boucle while pour exécuter ces étapes pour chaque tâche de 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);
}

Vous pouvez étendre cette version du programme dans la section Génération d'applications finies à la fin de la rubrique. Vous pouvez également suivre les instructions dans Téléchargement de l'application terminée pour télécharger le projet.

Avertissement

L'utilisation de WhenAny dans une boucle, comme décrit dans l'exemple, est parfait pour les problèmes qui impliquent un petit nombre de tâches.Toutefois, d'autres approches sont plus efficaces si vous avez un grand nombre de tâches à traiter.Pour plus d'informations et pour découvrir des exemples, consultez Traitement des résultats des tâches qui se terminent.

Téléchargement du code de démarrage

Vous pouvez télécharger le code de démarrage pour l'exemple depuis Exemple async : transition du .NET vers Windows. Si vous n'avez pas accès à Internet, suivez les instructions dans Génération du code de démarrage à la fin de cette rubrique pour créer le code de démarrage.

Après avoir téléchargé le code, ouvrez-le et exécutez-le en procédant comme suit.

  1. Décompressez le fichier que vous avez téléchargé, puis démarrez Visual Studio 2012.

  2. Dans la barre de menus, sélectionnez Fichier, Ouvrir, Projet/Solution.

  3. Accédez au dossier qui contient l'exemple de code décompressé, puis ouvrez le fichier solution (.sln) pour AsTaskWhenAnyDemoVB ou AsTaskWhenAnyDemoCS.

  4. Dans l' Explorateur de solutions, ouvrez le menu contextuel du projet SequentialBlogReader, puis choisissez Définir comme projet de démarrage.

  5. Appuyez sur la touche F5 pour générer et exécuter le projet.

  6. Exécutez le code plusieurs fois pour vérifier que les résultats s'affichent dans le même ordre à chaque fois.

Vous pouvez examiner le fichier MainPage.xaml.vb ou MainPage.xaml.cs dans la section Génération du code de démarrage à la fin de la rubrique.

L'exemple repose sur le lecteur de blog décrit dans Démarrage rapide : appel d'API asynchrones en C# ou Visual Basic. Toutefois, le code de démarrage pour cette rubrique télécharge plusieurs publications de blog au lieu d'une seule.

Pour plus d'informations sur une large gamme d'améliorations et d'extensions que vous pouvez apporter à l'application, consultez Créer un lecteur de blog.

Téléchargement de l'application terminée

Si vous ne souhaitez pas créer l'exemple vous-même, vous pouvez télécharger l'exemple complet. Suivez les instructions de la section Téléchargement du code de démarrage, mais choisissez WhenAnyBlogReader comme Projet de démarrage.

Exécutez le programme plusieurs fois pour vérifier que les publications de blog apparaissent dans des ordres différents.

Vous pouvez examiner le fichier MainPage.xaml.vb ou MainPage.xaml.cs dans la section Génération d'applications finies à la fin de la rubrique.

Génération du code de démarrage

Vous pouvez télécharger les exemples de cette rubrique depuis Exemple async : transition du .NET vers Windows. Si vous préférez installer l'application vous-même, utilisez la procédure suivante.

  1. Démarrez Visual Studio 2012.

  2. Dans la barre de menus, sélectionnez Fichier, Nouveau, Projet.

    La boîte de dialogue Nouveau projet s'affiche.

  3. Dans la catégorie Installé, Modèles, choisissez Visual Basic ou Visual C#, puis Windows Store dans la liste des types de projets.

  4. Dans la liste des types de projet, choisissez Application vide (XAML).

  5. Nommez le projet SequentialBlogReader, puis cliquez sur OK.

    Le nouveau projet s'affiche dans l'Explorateur de solutions.

  6. Dans l'Explorateur de solutions, ouvrez le menu contextuel de MainPage.xaml, puis choisissez Ouvrir.

  7. Dans la fenêtre XAML de MainPage.xaml, remplacez le code par le code suivant.

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

    Une fenêtre simple qui contient une zone de texte et un bouton apparaît dans la fenêtre Design de MainPage.xaml.

    Pour plus d'informations sur une large gamme d'améliorations et d'extensions que vous pouvez apporter à l'interface utilisateur, consultez Créer un lecteur de blog.

  8. Dans l'Explorateur de solutions, ouvrez le menu contextuel de MainPage.xaml.vb ou MainPage.xaml.cs, puis choisissez Afficher le Code.

  9. Remplacez le code dans MainPage.xaml.vb ou MainPage.xaml.cs par le code suivant.

    ' 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. Choisissez la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer.

Génération de l'application terminée

Vous pouvez télécharger les exemples de cette rubrique depuis Exemple async : transition du .NET vers Windows. Si vous préférez installer l'application vous-même, utilisez la procédure suivante.

  1. Démarrez Visual Studio 2012.

  2. Dans la barre de menus, sélectionnez Fichier, Nouveau, Projet.

    La boîte de dialogue Nouveau projet s'affiche.

  3. Dans la catégorie Installé, Modèles, choisissez Visual Basic ou Visual C#, puis Windows Store.

  4. Dans la liste des types de projet, choisissez Application vide (XAML).

  5. Nommez le projet WhenAnyBlogReader, puis cliquez sur OK.

    Le nouveau projet s'affiche dans l'Explorateur de solutions.

  6. Dans l'Explorateur de solutions, ouvrez le menu contextuel de MainPage.xaml, puis choisissez Ouvrir.

  7. Dans la fenêtre XAML de MainPage.xaml, remplacez le code par le code suivant.

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

    Une fenêtre simple qui contient une zone de texte et un bouton apparaît dans la fenêtre Design de MainPage.xaml.

    Pour plus d'informations sur une large gamme d'améliorations et d'extensions que vous pouvez apporter à l'application, consultez Créer un lecteur de blog.

  8. Dans l'Explorateur de solutions, ouvrez le menu contextuel de MainPage.xaml.vb ou MainPage.xaml.cs, puis choisissez Afficher le Code.

  9. Remplacez le code dans MainPage.xaml.vb ou MainPage.xaml.cs par le code suivant.

    ' 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. Choisissez la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer.

Voir aussi

Référence

WhenAny``1

AsTask``1

Concepts

Programmation asynchrone avec Async et Await (C# et Visual Basic)

Annuler les tâches Asynch restantes lorsque l'une d'elles est terminée (C# et Visual Basic)

Démarrer plusieurs tâches Asynch et les traiter une fois terminées (C# et Visual Basic)

Autres ressources

Démarrage rapide : utilisation de l'opérateur await pour la programmation asynchrone

Créer un lecteur de blog

IAsyncOperationWithProgress