WhenAny: Überbrückung zwischen .NET Framework und Windows-Runtime (C# und Visual Basic)

In dem Beispiel in diesem Thema wird ein Windows-Runtime-Typ, der Blogfeeds herunterlädt, asynchron mit einer .NET Framework-Methode kombiniert, die asynchrone Aufgaben in der Reihenfolge verarbeitet, in der sie abgeschlossen werden. Weitere Informationen zu dem Typ finden Sie in dem Thema zu SyndicationClient. Weitere Informationen zur Methode finden Sie unter Task.WhenAny.

Durch Kombination dieser Funktionen kann der Download mehrerer Blogfeeds gleichzeitig gestartet werden, und die Ergebnisse können verarbeitet werden, wenn die Downloads abgeschlossen sind. Wenn ein Feed schneller als die anderen heruntergeladen wird, werden seine Ergebnisse zuerst angezeigt. Wenn Sie eine SyndicationClient-Methode verwenden, können Sie die Feeds noch einfacher herunterladen. Durch Verwendung der Task.WhenAny-Methode kann der nächste Feed, dessen Download abgeschlossen ist, problemlos ermittelt werden.

Hinweis

Für die Ausführung des Beispiels muss Windows 8 auf dem Computer installiert sein.Wenn Sie das Beispiel aus Visual Studio heraus ausführen möchten, muss Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 für Windows 8 oder Visual Studio Express 2013 für Windows installiert sein.

Der folgende Code kombiniert diese Funktionen aus Windows-Runtime und .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();
}

Die in dem Beispiel erzeugte Ausgabe ähnelt den folgenden Zeilen. Für jeden Blog wird der Blogtitel gefolgt von den Titeln und Datumsangaben der Blogbeiträge angezeigt.

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

Im Rest dieses Themas werden Informationen zur Erstellung und Funktionsweise des Beispiels bereitgestellt.

Visual Studio 2012 und Windows 8 müssen auf dem Computer installiert sein, damit diese App ausgeführt werden kann.

Dieses Thema enthält folgende Abschnitte.

  • Optionen für das Beispiel einrichten
  • Verstehen des Startcodes
  • Erweitern des Startcodes
  • Herunterladen des Startcodes
  • Herunterladen der fertigen App
  • Erstellen des Startcodes
  • Erstellen der fertigen App
  • Verwandte Themen

Optionen für das Beispiel einrichten

Das Beispiel basiert auf dem Blogreader, der in dem Schnellstart-Thema zur Verwendung des await-Operators für die asynchrone Programmierung beschrieben wird. Der in diesem Thema gezeigte Startcode lädt jedoch nicht nur einen, sondern mehrere Blogfeeds herunter.

Der Startcode verwendet die Windows-Runtime-Funktionalität, um die Blogfeeds sequenziell herunterzuladen. Das heißt, dass die Blogfeeds in der Reihenfolge heruntergeladen werden, in der sie in einer URL-Auflistung aufgeführt sind. Die fertige App fügt Funktionen aus .NET Framework hinzu, um die Blogfeeds in der Reihenfolge herunterzuladen, in der sie abgeschlossen werden.

Zum Einrichten des Beispielcodes stehen folgende Möglichkeiten zur Verfügung:

  • Startcode.

    • Sie können den Startcode herunterladen, indem Sie die Anweisungen unter Herunterladen des Startcodes befolgen.

    • Sie können den Startcode selbst erstellen, indem Sie die Anweisungen unter Erstellen des Startcodes befolgen.

    • Sie können den Startcode überprüfen, ohne ihn zu implementieren, indem Sie einen Bildlauf zu Erstellen des Startcodes durchführen.

  • Fertige App.

    • Sie können die fertige App herunterladen, indem Sie die Anweisungen unter Herunterladen der fertigen App befolgen.

    • Sie können die App selbst erstellen, indem Sie die Anweisungen unter Erstellen der fertigen App befolgen.

    • Sie können die fertige App überprüfen, ohne sie zu implementieren, indem Sie einen Bildlauf zu Erstellen der fertigen App durchführen.

In dem Abschnitt Verstehen des Startcodes werden wichtige Punkte in der Basislösung erläutert.

In dem Abschnitt Erweitern des Startcodes wird gezeigt, wie Sie den Code durch Hinzufügen von AsTask``2 und Task.WhenAny ändern.

Verstehen des Startcodes

Der Startcode verwendet die SyndicationClient-Methode RetrieveFeedAsync, um einen Blogfeed von den einzelnen URIs in einer Liste von URIs herunterzuladen. Jeder Aufruf der Methode gibt eine IAsyncOperationWithProgress-Instanz zurück, die einen laufenden asynchronen Vorgang darstellt. Wenn er erwartet wird, erzeugt der asynchrone Vorgang eine SyndicationFeed-Instanz, die Informationen über den heruntergeladenen Blogfeed enthält.

Der Code definiert eine Abfrage, die RetrieveFeedAsync auf jeden Eintrag in einer Liste von URIs anwendet. Wenn sie ausgeführt wird, gibt die Abfrage eine Auflistung von IAsyncOperationWithProgress-Instanzen zurück.

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 führt die Abfrage aus und startet die asynchronen Prozesse. Siehe dazu folgendes Codebeispiel:

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

Sie haben jetzt eine Liste aktiver IAsyncOperationWithProgress-Instanzen. Sie müssen noch warten, bis die einzelnen Instanzen die Endergebnisse abrufen.

Die folgende Schleife wartet ab, bis die einzelnen IAsyncOperationWithProgress-Instanzen die SyndicationFeed-Ergebnisse abrufen.

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

Diese Version des Programms wird im Abschnitt Erstellen des Startcodes am Ende des Themas behandelt.

Weitere Informationen zum Programmieren mit asynchronen Windows-Runtime-APIs finden Sie in dem Schnellstart-Thema zur Verwendung des await-Operators für die asynchrone Programmierung.

Erweitern des Startcodes

Der Startcode zeigt, dass SyndicationClient das Herunterladen von Blogfeeds vereinfacht. Der letzte Schritt in diesem Beispiel besteht darin, es der Anwendung zu ermöglichen, die Blogfeeds in der Reihenfolge zu verarbeiten, in der die Downloads abgeschlossen werden, statt in der Reihenfolge, in der sie in der URI-Liste angezeigt werden.

Der Schlüssel für die Erweiterung ist die Task.WhenAny-Methode. Wenn Sie WhenAny auf eine Auflistung asynchroner Prozesse anwenden, gibt die Methode den ersten abgeschlossenen Prozess zurück, wodurch Ihre Wartezeit minimiert wird. In diesem Beispiel ist die Reihenfolge, in der die Blogfeedinformationen angezeigt werden, nicht wichtig. Wenn ein Download langsam ist, können die Ergebnisse aus einem anderen Blog zuerst angezeigt werden. Die Situation scheint perfekt für WhenAny, mit Ausnahme eines Aspekts: WhenAny erfordert eine Auflistung von Aufgaben.

Aufrufen von AsTask

WhenAny erfordert eine Auflistung von Task- oder Task-Instanzen, aber die SyndicationClient-Methode, die die Blogfeeds herunterlädt, gibt eine IAsyncOperationWithProgress-Instanz zurück. Daher muss die App zwischen den IAsyncOperationWithProgress-Objekten aus Windows-Runtime und den Task-Objekten aus .NET Framework überbrücken.

.NET Framework stellt AsTask``2-Erweiterungsmethoden für den Übergang bereit. Wenn Sie AsTask in einer IAsyncOperationWithProgress-Instanz aufrufen, gibt AsTask eine Aufgabe zurück, die den asynchronen Vorgang darstellt. Die Aufgabe wird abgeschlossen, wenn die entsprechende IAsyncOperationWithProgress-Instanz abgeschlossen wird und die Aufgabe über das Ergebnis oder die Ausnahme der Instanz verfügt.

Daher rufen Sie nur AsTask in jeder IAsyncOperationWithProgress-Instanz auf, die RetrieveFeedAsync zurückgibt. Siehe dazu folgendes Codebeispiel: Der Code benennt die Variablen um, um die Änderung an Aufgaben wiederzugeben, und verwendet aus Gründen der Klarheit die explizite Typisierung.

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

Hinweis

AsTask spielt eine wichtige Rolle in der asynchronen Programmierung, deren Sie sich möglicherweise nicht bewusst sind.Der Compiler verwendet AsTask, wenn Sie einen await-Operator auf eine IAsyncAction- oder IAsyncOperation-Instanz anwenden. Siehe dazu folgendes Codebeispiel.

Anwenden von "WhenAny"

Der letzte Schritt in der Konvertierung besteht darin, der App die Task.WhenAny-Methode hinzuzufügen. WhenAny wird auf eine Auflistung von Aufgaben (blogFeedTasksList) angewendet und gibt die erste Aufgabe in der Auflistung zurück, die abgeschlossen wird. Genauer gesagt gibt WhenAny eine Aufgabe zurück, die – sofern sie erwartet wird – als die Aufgabe ausgewertet wird, die zuerst beendet wurde.

Die folgende Anweisung ruft WhenAny auf und wartet auf das Ergebnis. Der Code verwendet die explizite Typisierung, um das Ergebnis deutlicher anzuzeigen.

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

Der folgende Code führt die gleiche Aufgabe aus wie die vorherige Anweisung, unterteilt den Vorgang jedoch in zwei Anweisungen, um ihn deutlicher zu machen. Die erste Anweisung ruft WhenAny auf, und die zweite Anweisung wartet auf das Ergebnis.

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

Abschließend müssen Sie abwarten, dass nextTask die Ergebnisse (eine SyndicationFeed-Instanz) aus der zuerst beendeten Aufgabe abruft. Dann müssen Sie nextTask aus der Liste entfernen, damit keine erneute Verarbeitung erfolgt.

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

Verwenden Sie eine While-Schleife, um diese Schritte für jede Aufgabe in blogFeedTasksList auszuführen.

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

Diese Version des Programms wird im Abschnitt Erstellen der fertigen App am Ende des Themas behandelt. Alternativ dazu können Sie die Anweisungen unter Herunterladen der fertigen App befolgen, um das Projekt herunterzuladen.

Warnung

Die Verwendung von WhenAny in einer Schleife gemäß der Beschreibung im Beispiel eignet sich gut für Probleme, die nur wenige Aufgaben umfassen.Andere Ansätze sind jedoch effizienter, wenn viele Aufgaben verarbeitet werden müssen.Weitere Informationen und Beispiele finden Sie in dem Thema zur Verarbeitung von Aufgaben nach deren Abschluss.

Herunterladen des Startcodes

Sie können den Startcode für das Beispiel unter dem Thema mit einem asynchronen Beispiel für die Überbrückung zwischen .NET und Windows herunterladen. Wenn Sie keinen Zugriff auf das Internet haben, befolgen Sie die Anweisungen unter Erstellen des Startcodes am Ende dieses Themas, um den Startcode zu erstellen.

Nachdem Sie den Code heruntergeladen haben, öffnen Sie ihn, und führen Sie ihn mit den folgenden Schritten aus.

  1. Dekomprimieren Sie die Datei, die Sie heruntergeladen haben, und starten Sie dann Visual Studio 2012.

  2. Klicken Sie in der Menüleiste auf Datei, dann auf Öffnen und Projekt/Projektmappe.

  3. Navigieren Sie zu dem Ordner, der den dekomprimierten Beispielcode enthält, und öffnen Sie die Projektmappendatei (SLN) für "AsTaskWhenAnyDemoVB" oder "AsTaskWhenAnyDemoCS".

  4. Im Projektmappen-Explorer öffnen Sie das Kontextmenü für das Projekt SequentialBlogReader und wählen dann Als Startprojekt festlegen aus.

  5. Drücken Sie zum Erstellen und Ausführen des Projekts die Taste F5.

  6. Führen Sie den Code mehrmals aus, um zu überprüfen, ob die Ergebnisse jedes Mal in der gleichen Reihenfolge angezeigt werden.

Die Datei "MainPage.xaml.vb" bzw. "MainPage.xaml.cs" wird im Abschnitt Erstellen des Startcodes am Ende des Themas aufgeführt.

Das Beispiel basiert auf dem Blogreader, der in dem Schnellstart-Thema zur Verwendung des await-Operators für die asynchrone Programmierung beschrieben wird. Der in diesem Thema gezeigte Startcode lädt jedoch nicht nur einen, sondern mehrere Blogfeeds herunter.

Informationen zu den zahlreichen Erweiterungen und Verbesserungen, die Sie an der Anwendung vornehmen können, finden Sie in dem Thema zum Erstellen eines Blogreaders.

Herunterladen der fertigen App

Wenn Sie das Beispiel nicht selbst erstellen möchten, können Sie das vollständige Beispiel herunterladen. Folgen Sie den Anweisungen im Abschnitt Herunterladen des Startcodes, wählen Sie jedoch WhenAnyBlogReader als Startprojekt aus.

Führen Sie das Programm mehrmals aus, um zu überprüfen, ob die Blogfeeds in verschiedenen Reihenfolgen angezeigt werden.

Die Datei "MainPage.xaml.vb" bzw. "MainPage.xaml.cs" wird im Abschnitt Erstellen der fertigen App am Ende des Themas aufgeführt.

Erstellen des Startcodes

Sie können die hier aufgeführten Beispiele in dem Thema mit einem asynchronen Beispiel für die Überbrückung zwischen .NET und Windows herunterladen. Wenn Sie es vorziehen, die Anwendung selbst einzurichten, führen Sie folgende Schritte aus.

  1. Starten Sie Visual Studio 2012.

  2. Wählen Sie in der Menüleiste Datei, Neu, Projekt aus.

    Das Dialogfeld Neues Projekt wird angezeigt.

  3. Wählen Sie in der Kategorie Installiert, Vorlagen den Eintrag Visual Basic oder Visual C# aus, und wählen Sie dann in der Liste der Projekttypen Windows Store aus.

  4. Wählen Sie in der Liste der Projekttypen Leere App (XAML) aus.

  5. Nennen Sie das Projekt SequentialBlogReader, und klicken Sie dann auf die Schaltfläche OK.

    Das neue Projekt wird im Projektmappen-Explorer angezeigt.

  6. Öffnen Sie im Projektmappen-Explorer das Kontextmenü für die MainPage.xaml-Datei, und wählen Sie Öffnen aus.

  7. Ersetzen Sie den automatisch generierten Code im Fenster XAML der MainPage.xaml-Datei durch den folgenden Code.

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

    Ein einfaches Fenster mit einem Textfeld und einer Schaltfläche wird im Fenster Entwurf von "MainPage.xaml" angezeigt.

    Informationen zu den zahlreichen Erweiterungen und Verbesserungen, die Sie an der UI vornehmen können, finden Sie in dem Thema zum Erstellen eines Blogreaders.

  8. Öffnen Sie im Projektmappen-Explorer das Kontextmenü für "MainPage.xaml.vb" oder "MainPage.xaml.cs", und wählen Sie dann Code anzeigen aus.

  9. Ersetzen Sie den Code in "MainPage.xaml.vb“ oder in "MainPage.xaml.cs" durch den folgenden Code.

    ' 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. Drücken Sie die Taste F5, um das Programm auszuführen, und klicken Sie dann auf die Schaltfläche Starten.

Erstellen der fertigen App

Sie können die hier aufgeführten Beispiele in dem Thema mit einem asynchronen Beispiel für die Überbrückung zwischen .NET und Windows herunterladen. Wenn Sie es vorziehen, die Anwendung selbst einzurichten, führen Sie folgende Schritte aus.

  1. Starten Sie Visual Studio 2012.

  2. Wählen Sie in der Menüleiste Datei, Neu, Projekt aus.

    Das Dialogfeld Neues Projekt wird angezeigt.

  3. Wählen Sie Visual Basic oder Visual C# in der Kategorie Installiert, Vorlagen aus, und wählen Sie dann Windows Store aus.

  4. Wählen Sie in der Liste der Projekttypen Leere App (XAML) aus.

  5. Nennen Sie das Projekt WhenAnyBlogReader, und klicken Sie dann auf die Schaltfläche OK.

    Das neue Projekt wird im Projektmappen-Explorer angezeigt.

  6. Öffnen Sie im Projektmappen-Explorer das Kontextmenü für die MainPage.xaml-Datei, und wählen Sie Öffnen aus.

  7. Ersetzen Sie den automatisch generierten Code im Fenster XAML der MainPage.xaml-Datei durch den folgenden Code.

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

    Ein einfaches Fenster mit einem Textfeld und einer Schaltfläche wird im Fenster Entwurf von "MainPage.xaml" angezeigt.

    Informationen zu den zahlreichen Erweiterungen und Verbesserungen, die Sie an der Anwendung vornehmen können, finden Sie in dem Thema zum Erstellen eines Blogreaders.

  8. Öffnen Sie im Projektmappen-Explorer das Kontextmenü für "MainPage.xaml.vb" oder "MainPage.xaml.cs", und wählen Sie dann Code anzeigen aus.

  9. Ersetzen Sie den Code in "MainPage.xaml.vb“ oder in "MainPage.xaml.cs" durch den folgenden Code.

    ' 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. Drücken Sie die Taste F5, um das Programm auszuführen, und klicken Sie dann auf die Schaltfläche Starten.

Siehe auch

Referenz

WhenAny``1

AsTask``1

Konzepte

Asynchrone Programmierung mit Async und Await (C# und Visual Basic)

Verbleibende asynchrone Aufgaben nach Abschluss einer Aufgabe abbrechen (C# und Visual Basic)

Mehrere asynchrone Aufgaben starten und nach Abschluss verarbeiten (C# und Visual Basic)

Weitere Ressourcen

Schnellstart-Thema zur Verwendung des await-Operators für die asynchrone Programmierung

Thema zum Erstellen eines Blogreaders

IAsyncOperationWithProgress