WhenAny:銜接 .NET Framework 和 Windows 執行階段 (C# 和 Visual Basic)
本主題中的範例結合 Windows 執行階段 類型,這個類型會使用依工作完成順序處理非同步工作的 .NET Framework 方法,以非同步方式下載部落格摘要。 如需類型的詳細資訊,請參閱 SyndicationClient。 如需方法的詳細資訊,請參閱 Task.WhenAny。
您可以結合這些功能,開始同時下載多個部落格摘要,並在完成時處理結果。 如果某個摘要比其他摘要更快速下載,其結果會先出現。 使用 SyndicationClient 方法,可以更輕鬆地下載摘要;使用 Task.WhenAny 方法,可以更輕鬆地識別下一個完成下載的摘要。
注意事項 |
---|
若要執行範例,您必須已在電腦上安裝 Windows 8。此外,如果您要從 Visual Studio 執行這個範例,也必須安裝 Visual Studio 2012、Visual Studio 2013、Visual Studio Express 2012 for Windows 8 或 Visual Studio Express 2013 for Windows。 |
下列程式碼會將 Windows 執行階段 和 .NET Framework 的下列功能合併:
SyndicationClient.RetrieveFeedAsync 會下載部落格摘要並傳回 IAsyncOperationWithProgress 執行個體。
AsTask``2 擴充方法會將 IAsyncOperationWithProgress 執行個體表示為 Task 執行個體。
WhenAny``1 會傳回識別工作集合中第一項要完成的工作。
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,才能執行這個應用程式。
本主題包含下列章節。
- 設定範例的選項
- 了解起始程式碼
- 擴充起始程式碼
- 下載起始程式碼
- 下載完成的應用程式
- 建立起始程式碼
- 建置完成的應用程式
- 相關主題
設定範例的選項
這個範例是根據快速入門:在 C# 或 Visual Basic 中呼叫非同步 API 中所述的部落格讀取器。 不過,本主題的起始程式碼下載多個部落格摘要 (而不是一個)。
起始程式碼使用 Windows 執行階段 功能循序下載部落格摘要。 也就是,部落格摘要是依照 URL 集合列出的順序下載。 完成的應用程式會加入 .NET Framework 中的功能,依部落格摘要完成順序下載摘要。
您可以使用下列任何方式來設定範例程式碼:
起始程式碼。
已經完成的應用程式。
您可以依照下載完成的應用程式中的指示,下載完成的應用程式。
您可以依照建置完成的應用程式中的指示,自行建置應用程式。
您可以捲動到建置完成的應用程式,檢閱完成的應用程式,而不需要進行實作。
了解起始程式碼一節會討論基本方案中的重點。
擴充入門程式碼一節說明如何藉由加入 AsTask``2 和 Task.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``1 會執行查詢並開始非同步處理序,如下列程式碼所示。
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);
}
您可以在本主題結尾,檢閱建置起始程式碼一節中這個版本的程式。
您可以在快速入門:在 C# 或 Visual Basic 中呼叫非同步 API中找到有關使用非同步 Windows 執行階段 應用程式開發介面進行非同步程式設計的詳細資訊。
擴充起始程式碼
起始程式碼示範 SyndicationClient 可讓您輕鬆下載部落格摘要。 完成這個範例的其餘步驟,就是要讓應用程式依照部落格摘要下載完成的順序,而非它們在 URI 清單中出現的順序來處理這些摘要。
完成增強功能的關鍵是 Task.WhenAny 方法。 當您將 WhenAny 套用至非同步處理序的集合時,方法會傳回第一個完成的程序,縮短您必須等候的時間。 在此範例中,部落格摘要資訊出現的順序並不重要。 如果其中一個下載緩慢,其他部落格的結果可能會先顯示。 這種情況似乎完全適合 WhenAny,除了一件事: WhenAny 需要工作集合。
叫用 AsTask
WhenAny 需要 Task 或 Task 執行個體的集合,但是下載部落格摘要的 SyndicationClient 方法會傳回 IAsyncOperationWithProgress 執行個體。 因此,應用程式必須在 Windows 執行階段 的 IAsyncOperationWithProgress 物件和 .NET Framework 的 Task 物件之間進行橋接。
.NET Framework 提供 AsTask``2 擴充方法進行轉換。 當您在 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 在非同步程式設計中扮演重要且可能不為人知的角色。每當您將等候運算子套用至 IAsyncAction 或 IAsyncOperation 執行個體時,編譯器就會使用 AsTask,如下列程式碼所示。
|
套用 WhenAny
轉換中的最後一個步驟是將 Task.WhenAny 方式加入至應用程式。 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);
}
您可以在本主題結尾,檢閱建置完成的應用程式一節中這個版本的程式。 或者,您可以依照下載完成的應用程式中的指示下載專案。
警告
在迴圈中使用 WhenAny (如本範例所述) 很適合涉及少量工作的問題。不過,如果您需要處理大量工作,其他方法會更有效率。如需詳細資訊和範例,請參閱當工作完成時處理工作。
下載起始程式碼
您可以從非同步範例:從 .NET 銜接 Windows 下載範例的起始程式碼。 如果您無法存取網際網路,請依照本主題結尾建立起始程式碼中的指示,建立起始程式碼。
在您下載程式碼之後,請執行下列步驟,開啟及執行它。
解壓縮您下載的檔案,然後啟動 Visual Studio 2012。
在功能表列上,選擇 [檔案]、[開啟]、[專案/方案]。
巡覽至存放解壓縮的範例程式碼的資料夾,並開啟 AsTaskWhenAnyDemoVB 或 AsTaskWhenAnyDemoCS 的方案檔 (.sln)。
在 [方案總管],開啟 [SequentialBlogReader] 專案的捷徑功能表,然後選取 [設定為啟始專案]。
選擇 F5 鍵以建置和執行專案。
執行程式碼數次以驗證結果每次都按照相同順序出現。
您可以在本主題結尾,檢閱建置起始程式碼一節中的 MainPage.xaml.vb 或 MainPage.xaml.cs 檔案。
這個範例是根據快速入門:在 C# 或 Visual Basic 中呼叫非同步 API 中所述的部落格讀取器。 不過,本主題的起始程式碼下載多個部落格摘要 (而不是一個)。
如需可對應用程式執行各種改善和擴充的詳細資訊,請參閱建立部落格閱讀程式。
下載完成的應用程式
如果您不要自行建立這個範例,您可以下載完整範例。 請依照下載起始程式碼一節中的指示,不過,選取 WhenAnyBlogReader 為 [啟始專案]。
執行程式數次以驗證部落格摘要按照不同順序出現。
您可以在本主題結尾,檢閱建置完成的應用程式一節中的 MainPage.xaml.vb 或 MainPage.xaml.cs 檔案。
建立起始程式碼
您可以從非同步範例:從 .NET 銜接 Windows 下載本主題中的範例。 如果您想要自行設定應用程式,請遵循下列步驟。
啟動 Visual Studio 2012。
在功能表列上,選擇 [檔案]、[新增]、[專案]。
[新增專案] 對話方塊隨即開啟。
在 [已安裝的]、[範本] 分類中,選擇 [Visual Basic] 或 [Visual C#],然後選擇專案類型清單中的 [Windows 市集]。
從專案類型清單中選擇 [空白應用程式 (XAML)]。
將專案命名為 SequentialBlogReader,然後選擇 [確定] 按鈕。
新專案即會出現於 [方案總管] 中。
在 [方案總管] 中,開啟 MainPage.xaml 的捷徑功能表,然後選擇 [開啟]。
在 MainPage.xaml [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 執行各種改善和擴充的詳細資訊,請參閱建立部落格閱讀程式。
在 [方案總管] 中,開啟 MainPage.xaml.vb 或 MainPage.xaml.cs 的捷徑功能表,然後選擇 [檢視程式碼]。
在 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"; } } }
選取 F5 鍵執行程式,然後選擇 [開始] 按鈕。
建置完成的應用程式
您可以從非同步範例:從 .NET 銜接 Windows 下載本主題中的範例。 如果您想要自行設定應用程式,請遵循下列步驟。
啟動 Visual Studio 2012。
在功能表列上,選擇 [檔案]、[新增]、[專案]。
[新增專案] 對話方塊隨即開啟。
在 [已安裝的]、[範本] 分類中,選擇 [Visual Basic] 或 [Visual C#],然後 [Windows 市集]。
從專案類型清單中選擇 [空白應用程式 (XAML)]。
將專案命名為 WhenAnyBlogReader,然後選擇 [確定] 按鈕。
新專案即會出現於 [方案總管] 中。
在 [方案總管] 中,開啟 MainPage.xaml 的捷徑功能表,然後選擇 [開啟]。
在 MainPage.xaml [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 [設計] 檢視中。
如需可對應用程式執行各種改善和擴充的詳細資訊,請參閱建立部落格閱讀程式。
在 [方案總管] 中,開啟 MainPage.xaml.vb 或 MainPage.xaml.cs 的捷徑功能表,然後選擇 [檢視程式碼]。
在 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"; } } }
選取 F5 鍵執行程式,然後選擇 [開始] 按鈕。
請參閱
參考
概念
使用 Async 和 Await 設計非同步程式 (C# 和 Visual Basic)
當其中一項工作完成時,取消剩餘的非同步工作 (C# 和 Visual Basic)
啟動多項非同步工作並在它們完成時進行處理 (C# 和 Visual Basic)