WhenAny:.NET Framework 和 Windows 运行时之间的桥接(C# 和 Visual Basic)

本主题中的示例将下载博客源以异步方式与 .NET framework 方法处理异步任务按顺序完成它们的 Windows 运行时 类型。有关类型的更多信息,请参见 SyndicationClient。有关方法的更多信息,请参见 Task.WhenAny

通过将这些功能,可以启动同时下载多个博客源和处理结果,但完成。如果一个源比其他快速下载,其结果首先出现。使用 SyndicationClient 方法,您可以更轻松地下载源;使用 Task.WhenAny 方法,您可以更轻松地标识完成下载的下源。

说明说明

若要运行此示例,必须在计算机上安装 8 的窗口。此外,因此,如果要从 Visual Studio 运行测试的示例,还必须拥有 Visual Studio 2012 或 Visual Studio express 2012 中的 windows 8 安装。

下面的代码将 Windows 运行时 和 .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();
}

示例产生类似于下面的行的输出。对于每个博客,则显示标题和日期执行博客中的前缀的博客文章。

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

本主题其余部分提供有关如何的详细信息创建该示例,以及如何工作。

必须在计算机上安装 Visual Studio 2012 和 Windows 8 才能运行此应用程序。

本主题包括下列各节。

  • 示例的设置选项
  • 了解起始代码
  • 扩展起始代码
  • 要下载的初学者工具包代码
  • 下载完毕的 App
  • 生成启动程序代码
  • 生成完成的 App
  • 相关主题

示例的设置选项

该示例依据中描述的博客 快速入门:使用异步编程的时间运算符读取器。但是,此主题中的起始代码下载多个博客源而不是一个。

下载博客中的起始代码使用 Windows 运行时 函数按顺序提供。即博客源按 URL 中的集合列表中的顺序下载。已完成的 app 从 .NET Framework 添加功能下载博客源它们完成的顺序。

可以设置代码示例通过以下任一方式:

  • 起始代码。

    • 您可以按照在 要下载的初学者工具包代码的命令下载起始代码,

    • 可以遵循中的说明创建起始代码在 生成启动程序代码。

    • 可以查看起始代码,而无需实现它通过移动到 生成启动程序代码。

  • 完成 app 的。

    • 您可以按照在 下载完毕的 App的命令下载已完成的应用程序

    • 您可以按照命令生成该应用程序在 生成完成的 App。

    • 您可以查看已完成的应用程序,而无需实现它通过移动到 生成完成的 App。

了解起始代码 部分。这个基本人员讨论关键点。

扩展起始代码 节演示如何通过添加 AsTaskTask.WhenAny修改代码。

了解起始代码

启动程序代码使用一个 SyndicationClient 方法,RetrieveFeedAsync即,可从每 URI 的博客源在 URI 列表。每个调用该方法返回一个连续的异步操作的 IAsyncOperationWithProgress 实例。当等待,异步操作以包含有关下载的博客源的信息的 SyndicationFeed 实例。

代码定义应用 RetrieveFeedAsync 于 URI 列表的每一项的查询。执行时,该查询返回 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<TSource> 运行查询并启动异步过程。

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

此时,您具有有效的 IAsyncOperationWithProgress 实例列表。您还必须等待每个实例获取最终结果。

下面的循环等待每 IAsyncOperationWithProgress 实例检索 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);
}

可以查看程序的此版本在 Building the Starter Code 节中的主题末尾的。

可以找到有关编程的更多信息与异步 快速入门:使用异步编程的时间运算符Windows 运行时 API。

扩展起始代码

起始代码演示,SyndicationClient 便于下载博客源。完成该示例中使用的其余步骤将启用应用程序处理博客源它们下载完整而不是顺序显示 URI 的列出顺序。

对于完成这种增强的键是 Task.WhenAny 方法。当应用时将集合的 WhenAny 的异步过程,方法返回已完成的第一个过程,最大程度地减少必须等待的时间。在此示例中,博客源消息的顺序并不重要。如果一个下载很慢,从其他博客的结果可能首先显示。这种情况是理想到 WhenAny 但一点:WhenAny 需要任务的集合。

JJ635140.collapse_all(zh-cn,VS.110).gif调用 AsTask

WhenAny 需要 TaskTask<TResult> 实例的集合,但是,下载博客源的 SyndicationClient 方法返回 IAsyncOperationWithProgress 实例。因此,该应用程序必须它们在从 Windows 运行时 的 IAsyncOperationWithProgress 对象和从 .NET framework 的 Task 对象之间。

.NET framework 提供 AsTask 扩展方法使该转换。当您调用 IAsyncOperationWithProgress 实例时的 AsTask,AsTask 它返回一个表示异步操作的任务。任务完成,如果相应的 IAsyncOperationWithProgress 实例完成,并且,任务的实例的结果或异常。

因此,调用在 RetrieveFeedAsync 返回的每 IAsyncOperationWithProgress 实例的 AsTask,如以下代码所示。代码将变量重命名反映任务的更改并使用显式为清楚起见键入。

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

AsTask 编程中的"方面扮演着重要的角色您可能不知道。编译器使用 AsTask,只要应用一个等待运算符应用于 IAsyncAction 或 IAsyncOperation 实例中,在中,如以下代码所示。

JJ635140.collapse_all(zh-cn,VS.110).gif应用 WhenAny

最后一步在转换将添加 Task.WhenAny 方法为 app。WhenAny 适用于任务 (blogFeedTasksList) 集合并返回该完成的集合的第一个任务。具体而言,WhenAny 返回,那么,当等待,因此计算结果为任务首先完成的任务。

下面的语句以调用 WhenAny 并等待其结果。代码使用更清晰地显示结果的显式类型。

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

下面的代码执行操作与以前声明,但不中断相同操作。两个语句阐明所发生的情况。第一个语句也会调用,WhenAny,第二个语句等待结果。

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

最后,您必须等待 nextTask 从首先完成的任务检索结果 ( SyndicationFeed 实例),则必须然后从列表中移除 nextTask,以便不再处理它。

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

使用 while 循环执行每个任务的这些步骤。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);
}

可以查看程序的此版本在 生成完成的 App 节中的主题末尾的。也可以按照 下载完毕的 App 的命令下载该项目。

警告说明警告

使用在一个循环的 WhenAny,如该示例所述,运行良好为涉及少量的任务的问题。但是,因此,如果需要处理,则大量任务其他方法更为有效的。有关更多信息和示例,请参见 处理任务作为完

要下载的初学者工具包代码

可下载示例的启动程序中的代码 Async 示例:它们从 .NET 到窗口。如果您无法访问 Internet 的,请按照 生成启动程序代码 的命令本主题末尾创建起始代码。

在下载代码后,您打开并通过执行以下步骤来。

  1. 对要下载的文件,然后启动 Visual Studio 2012。

  2. 在菜单栏上,依次选择**“文件”“打开”“项目/解决方案”**。

  3. 导航到保存进行解压缩的代码示例中的文件夹,然后打开 AsTaskWhenAnyDemoVB 或 AsTaskWhenAnyDemoCS 的解决方案 (.sln) 文件。

  4. 解决方案资源管理器,打开 SequentialBlogReader 项目的快捷菜单,然后选择 设为启动项目

  5. 选择 F5 键生成和运行项目。

  6. 运行代码多次验证结果以相同顺序每次出现。

您可以查看在 生成启动程序代码 部分的 MainPage.xaml.vb 或 MainPage.xaml.cs 文件在主题末尾的。

该示例依据中描述的博客 快速入门:使用异步编程的时间运算符读取器。但是,此主题中的起始代码下载多个博客源而不是一个。

有关可以对应用程序的多种增强功能和扩展的信息,请参见 创建一个博客阅读器

下载完毕的 App

如果不希望生成该示例,您可以下载完整示例。按照 要下载的初学者工具包代码 一节中的说明,但是,选择 WhenAnyBlogReader 作为 启动项目

运行程序多次验证博客源采用不同的顺序。

您可以查看在 生成完成的 App 部分的 MainPage.xaml.vb 或 MainPage.xaml.cs 文件在主题末尾的。

生成启动程序代码

可以下载本主题中的示例从 Async 示例:它们从 .NET 到窗口。如果您希望将您的应用程序,请执行以下步骤。

  1. 启动 Visual Studio 2012。

  2. 在菜单栏上,选择**“文件”“新建**、“项目”

    将打开**“新建项目”**对话框。

  3. 已安装模板 类别中,选择 Visual BasicVisual C#,然后选择项目类型列表中 Windows 应用商店

  4. 在"项目类型列表中,选择 空白应用程序 (XAML)

  5. 将项目命名为 SequentialBlogReader,然后选择 确定 按钮。

    新项目出现在**“解决方案资源管理器”**中。

  6. 解决方案资源管理器,打开 MainPage.xaml 的快捷菜单,然后选择 打开

  7. XAML 窗口 MainPage.xaml 中,用下面的代码替换代码。

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

    包含文本框和一个按钮的简单窗口显示 设计 窗口 MainPage.xaml。

    有关可以对 UI 的各种改进和扩展的信息,请参见 创建一个博客阅读器

  8. 解决方案资源管理器,打开 MainPage.xaml.vb 或 MainPage.xaml.cs 的快捷菜单,然后选择 查看代码

  9. 用下面的代码替换该 MainPage.xaml.vb 或 MainPage.xaml.cs 的代码。

    ' 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. 选择 F5 键运行程序,然后选择 启动 按钮。

生成完成的 App

可以下载本主题中的示例从 Async 示例:它们从 .NET 到窗口。如果您希望将您的应用程序,请执行以下步骤。

  1. 启动 Visual Studio 2012。

  2. 在菜单栏上,选择**“文件”“新建**、“项目”

    将打开**“新建项目”**对话框。

  3. 已安装模板 类别中,选择 Visual BasicVisual C#,然后选择 Windows 应用商店

  4. 从项目类型列表中,选择 空白应用程序 (XAML)

  5. 将项目命名为 WhenAnyBlogReader,然后选择 确定 按钮。

    新项目出现在**“解决方案资源管理器”**中。

  6. 解决方案资源管理器,打开 MainPage.xaml 的快捷菜单,然后选择 打开

  7. XAML 窗口 MainPage.xaml 中,用下面的代码替换代码。

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

    包含文本框和一个按钮的简单窗口显示 设计 窗口 MainPage.xaml。

    有关可以对应用程序的多种增强功能和扩展的信息,请参见 创建一个博客阅读器

  8. 解决方案资源管理器,打开 MainPage.xaml.vb 或 MainPage.xaml.cs 的快捷菜单,然后选择 查看代码

  9. 用下面的代码替换该 MainPage.xaml.vb 或 MainPage.xaml.cs 的代码。

    ' 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. 选择 F5 键运行程序,然后选择 启动 按钮。

请参见

参考

WhenAny

AsTask

概念

使用 Async 和 Await 的异步编程(C# 和 Visual Basic)

在完成一个任务后取消剩余任务(C# 和 Visual Basic)

启动多个任务并在其完成时进行处理(C# 和 Visual Basic)

其他资源

快速入门:使用异步编程的时间运算符

创建一个博客阅读器

IAsyncOperationWithProgress