取消作業:銜接 .NET Framework 和 Windows 執行階段 (C# 和 Visual Basic)
您可以結合 .NET Framework 與 Windows 執行階段中功能讓您的資源。本主題中的範例示範如何使用 .NET FrameworkCancellationToken 執行個體將取消按鈕設定為使用 Windows 執行階段 方法下載從網路的網誌饋送的應用程式。
注意事項 |
---|
若要執行這個範例,必須在電腦上安裝 Windows 8。此外,因此,如果您要從 Visual Studio 執行這個範例,您也必須在 Visual Studio 2012 已安裝或 Visual Studio Express 2012 for Windows 8 。 |
AsTask 提供橋接器
取消語彙基元要求 Task 執行個體,不過, Windows 執行階段 方法產生 IAsyncOperationWithProgress 執行個體。您可以使用 .NET Framework AsTask 擴充方法橋接這兩者。
在此範例中的 DownloadBlogsAsync 方法完成大部分的工作。
Async Function DownloadBlogsAsync(ct As CancellationToken) As Task
Dim client As Windows.Web.Syndication.SyndicationClient = New SyndicationClient()
Dim uriList = CreateUriList()
' Force the SyndicationClient to download the information.
client.BypassCacheOnRetrieve = True
' The following code avoids the use of implicit typing (var) so that you
' can identify the types clearly.
For Each uri In uriList
' ***These three lines are combined in the single statement that follows them.
'Dim feedOp As IAsyncOperationWithProgress(Of SyndicationFeed, RetrievalProgress) =
' client.RetrieveFeedAsync(uri)
'Dim feedTask As Task(Of SyndicationFeed) = feedOp.AsTask(ct)
'Dim feed As SyndicationFeed = Await feedTask
' ***You can combine the previous three steps in one expression.
Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(uri).AsTask(ct)
DisplayResults(feed, ct)
Next
End Function
async Task DownloadBlogsAsync(CancellationToken ct)
{
Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();
var uriList = CreateUriList();
// Force the SyndicationClient to download the information.
client.BypassCacheOnRetrieve = true;
// The following code avoids the use of implicit typing (var) so that you
// can identify the types clearly.
foreach (var uri in uriList)
{
// ***These three lines are combined in the single statement that follows them.
//IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> feedOp =
// client.RetrieveFeedAsync(uri);
//Task<SyndicationFeed> feedTask = feedOp.AsTask(ct);
//SyndicationFeed feed = await feedTask;
// ***You can combine the previous three steps in one expression.
SyndicationFeed feed = await client.RetrieveFeedAsync(uri).AsTask(ct);
DisplayResults(feed);
}
}
在迴圈的註解的部分詳細顯示轉換步驟。
要啟動的 SyndicationClient.RetrieveFeedAsync 呼叫下載從指定的 URI 建立部落格摘要的非同步作業。非同步作業是 IAsyncOperationWithProgress 的執行個體。
Dim feedOp As IAsyncOperationWithProgress(Of SyndicationFeed, RetrievalProgress) = client.RetrieveFeedAsync(uri)
IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> feedOp = client.RetrieveFeedAsync(uri);
由於您要使用的 .NET Framework 的取消功能要求工作,程式碼會將 AsTask 表示 IAsyncOperationWithProgress 執行個體為 Task<TResult>。特別是,應用程式碼接受 CancellationToken 引數的 AsTask 多載。
Dim feedTask As Task(Of SyndicationFeed) = feedOp.AsTask(ct)
Task<SyndicationFeed> feedTask = feedOp.AsTask(ct);
最後, await 或 Await 運算子等候工作 SyndicationFeed 會擷取結果。
Dim feed As SyndicationFeed = Await feedTask
SyndicationFeed feed = await feedTask;
如需 AsTask,請參閱 WhenAny:銜接 .NET Framework 和 Windows 執行階段 (C# 和 Visual Basic)中的 擴充起始程式碼 。
問題值得注意
您可以檢閱整個範例會移動到本主題結尾,透過下載這個範例至本機電腦,或是建立範例。如需詳細資訊和指示,請參閱 設定範例。
因為您檢閱這個範例中,您將注意重點強調星號。我們建議您閱讀本節進一步了解這些點,,特別是如果您之前尚未使用 CancellationToken 。
若要實作取消按鈕,您的程式碼必須包含下列項目。
CancellationTokenSource 變數,則為 cts,在所有方法的範圍存取它。
Public NotInheritable Class MainPage Inherits Page ' ***Declare a System.Threading.CancellationTokenSource. Dim cts As CancellationTokenSource
public sealed partial class MainPage : Page { // ***Declare a System.Threading.CancellationTokenSource. CancellationTokenSource cts;
[移除] 按鈕的事件處理常式。事件處理常式會使用 CancellationTokenSource.Cancel 方法告知 cts ,當使用者要求取消。
' ***Add an event handler for the Cancel button. Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs) If cts IsNot Nothing Then cts.Cancel() ResultsTextBox.Text &= vbCrLf & "Downloads canceled by the Cancel button." End If End Sub
// ***Add an event handler for the Cancel button. private void CancelButton_Click(object sender, RoutedEventArgs e) { if (cts != null) { cts.Cancel(); ResultsTextBox.Text += "\r\nDownloads canceled by the Cancel button."; } }
[啟動] 按鈕的 StartButton_Click,這個事件的事件處理常式,包括下列動作。
事件處理常式執行個體化 CancellationTokenSource,否則為 cts。
cts = New CancellationTokenSource()
// ***Instantiate the CancellationTokenSource. cts = new CancellationTokenSource();
在對 DownloadBlogsAsync的呼叫,下載網誌饋送,程式碼將 ctsCancellationTokenSource.Token 屬性做為引數。如果要求取消, Token 屬性傳播訊息。
Await DownloadBlogsAsync(cts.Token)
await DownloadBlogsAsync(cts.Token);
對 DownloadBlogsAsync 的呼叫中包含之 OperationCanceledException 的 catch 區塊結果的 try-catch 陳述式上,當您選取 [移除] 按鈕時。非同步方法的呼叫端定義採取什麼動作。這個範例會顯示訊息。
下列程式碼會顯示完整的 try-catch 陳述式。
Try ' ***Send a token to carry the message if cancellation is requested. Await DownloadBlogsAsync(cts.Token) ' ***Check for cancellations. Catch op As OperationCanceledException ' In practice, this catch block often is empty. It is used to absorb ' the exception, ResultsTextBox.Text &= vbCrLf & "Cancellation exception bubbles up to the caller." ' Check for other exceptions. Catch ex As Exception ResultsTextBox.Text = "Page could not be loaded." & vbCrLf & "Exception: " & ex.ToString() End Try
try { // ***Send a token to carry the message if cancellation is requested. await DownloadBlogsAsync(cts.Token); } // ***Check for cancellations. catch (OperationCanceledException) { // In practice, this catch block often is empty. It is used to absorb // the exception, ResultsTextBox.Text += "\r\nCancellation exception bubbles up to the caller."; } // Check for other exceptions. catch (Exception ex) { ResultsTextBox.Text = "Page could not be loaded.\r\n" + "Exception: " + ex.ToString(); }
如先前所述本主題中, DownloadBlogsAsync 方法會呼叫 Windows 執行階段 方法,則為 RetrieveFeedAsync,並將 .NET Framework 擴充方法,則為 AsTask,則傳回的 IAsyncOperation 執行個體。AsTask 表示執行個體做為 Task,因此,您可以將取消語彙基元到非同步作業。請選擇 [移除] 按鈕時,語彙基元會傳送訊息。
請注意使用,則為 AsTask,程式碼可以將相同的 CancellationToken 執行個體加入至 Windows 執行階段 方法 (RetrieveFeedAsync) 和 .NET Framework 方法 (DownloadBlogsAsync)。
下列程式碼行顯示程式碼的這個部分。
Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(uri).AsTask(ct)
SyndicationFeed feed = await client.RetrieveFeedAsync(uri).AsTask(ct);
如果您無法移除應用程式,它會產生下列輸出。
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 Windows Restart and Recovery Recipe, 3/21/2011 2:13:24 PM -07:00 Extreme Windows Blog Samsung Series 9 27” PLS Display: Amazing Picture, 8/20/2012 2:41:48 PM -07:00 NVIDIA GeForce GTX 660 Ti Graphics Card: Affordable Graphics Powerhouse, 8/16/2012 10:56:19 AM -07:00 HP Z820 Workstation: Rising To the Challenge, 8/14/2012 1:57:01 PM -07:00 Blogging Windows Windows Upgrade Offer Registration Now Available, 8/20/2012 1:01:00 PM -07:00 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 Windows for your Business What Windows 8 RTM Means for Businesses, 8/1/2012 9:01:00 AM -07:00 Higher-Ed Learning with Windows 8, 7/26/2012 12:03:00 AM -07:00 Second Public Beta of App-V 5.0 Now Available with Office Integration, 7/24/2012 10:07:26 AM -07:00 Windows Experience Blog Tech Tuesday Live Twitter Chat with Microsoft Hardware, 8/20/2012 2:20:57 AM -07:00 New Colors and New Artist Series Mice from Microsoft Hardware, 8/15/2012 12:06:35 AM -07:00 Tech Tuesday Live Twitter Chat with HP on Keeping Kids Safe as They Head Back to School #winchat, 8/13/2012 12:24:18 PM -07:00 Windows Security Blog Dealing with Fake Tech Support & Phone Scams, 6/16/2011 1:53:00 PM -07:00 Combating social engineering tactics, like cookiejacking, to stay safer online, 5/28/2011 12:02:26 PM -07:00 Windows 7 is now Common Criteria Certified!, 4/27/2011 9:35:01 AM -07:00 Windows Home Server Blog Connecting Windows 8 Consumer Preview with Windows Home Server, 3/25/2012 9:06:00 AM -07:00 Viridian PC Systems announces two new server models are available to order, 10/3/2011 12:36:00 PM -07:00 PC Specialist to release Windows Home Server 2011, 9/27/2011 10:27:37 AM -07:00 Springboard Series Blog Windows 8 Is Ready For Your Enterprise, 8/16/2012 9:59:00 AM -07:00 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
如果您選擇 [移除] 按鈕,在應用程式完成下載內容之前,結果會類似下列的輸出。
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 Windows Restart and Recovery Recipe, 3/21/2011 2:13:24 PM -07:00 Extreme Windows Blog Samsung Series 9 27” PLS Display: Amazing Picture, 8/20/2012 2:41:48 PM -07:00 NVIDIA GeForce GTX 660 Ti Graphics Card: Affordable Graphics Powerhouse, 8/16/2012 10:56:19 AM -07:00 HP Z820 Workstation: Rising To the Challenge, 8/14/2012 1:57:01 PM -07:00 Blogging Windows Windows Upgrade Offer Registration Now Available, 8/20/2012 1:01:00 PM -07:00 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 Windows for your Business What Windows 8 RTM Means for Businesses, 8/1/2012 9:01:00 AM -07:00 Higher-Ed Learning with Windows 8, 7/26/2012 12:03:00 AM -07:00 Second Public Beta of App-V 5.0 Now Available with Office Integration, 7/24/2012 10:07:26 AM -07:00 Downloads canceled by the Cancel button. Cancellation exception bubbles up to the caller.
設定範例
您可以下載應用程式,建置自己或檢閱程式碼在這個主題的結尾,而不需要實作它。在您的電腦上安裝 Visual Studio 2012 和 Windows 8 上執行此應用程式。
下載完成的應用程式
解壓縮您下載的檔案,然後啟動 Visual Studio。
在功能表列上,選擇 [檔案]、[開啟]、[專案/方案]。
巡覽至保存解壓縮的範例程式碼的資料夾,然後開啟方案 (.sln) 檔。
選擇 F5 鍵建置及執行專案。
執行程式碼幾次驗證可以移除在不同的點。
建置完成的應用程式
啟動 Visual Studio。
在功能表列上,選擇 [檔案]、[新增]、[專案]。
[新增專案] 對話方塊隨即開啟。
在 [安裝] 中, [ [範本] 分類中,選取 [Visual Basic] 或 [Visual C#]],然後選取 [Windows 市集]。
從專案類型清單中,選取 [空白的應用程式 (XAML)]。
將專案命名為 BlogFeedWithCancellation,然後選擇 [OK] 按鈕。
新專案即會出現於 [方案總管] 中。
在 [方案總管] 中,開啟 MainPage.xaml 的捷徑功能表,然後選擇 [開啟]。
在 [XAML] 視窗中 MainPage.xaml,以下列程式碼取代程式碼。
<Page x:Class="BlogFeedWithCancellation.MainPage" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:BlogFeedWithCancellation" 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="Left" Margin="325,77,0,0" VerticalAlignment="Top" Click="StartButton_Click" Height="145" Background="#FFA89B9B" FontSize="36" Width="355" /> <Button x:Name="CancelButton" Content="Cancel" HorizontalAlignment="Left" Margin="684,77,0,0" VerticalAlignment="Top" Height="145" Background="#FFA89B9B" Click="CancelButton_Click" FontSize="36" Width="355" /> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" Margin="325,222,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="546" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" Width="711" /> </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 Tasks. Imports System.Threading.Tasks ' Add an Imports statement for CancellationToken. Imports System.Threading Public NotInheritable Class MainPage Inherits Page ' ***Declare a System.Threading.CancellationTokenSource. Dim cts As CancellationTokenSource Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) ResultsTextBox.Text = "" ' Prevent unexpected reentrance. StartButton.IsEnabled = False ' ***Instantiate the CancellationTokenSource. cts = New CancellationTokenSource() Try ' ***Send a token to carry the message if cancellation is requested. Await DownloadBlogsAsync(cts.Token) ' ***Check for cancellations. Catch op As OperationCanceledException ' In practice, this catch block often is empty. It is used to absorb ' the exception, ResultsTextBox.Text &= vbCrLf & "Cancellation exception bubbles up to the caller." ' Check for other exceptions. Catch ex As Exception ResultsTextBox.Text = "Page could not be loaded." & vbCrLf & "Exception: " & ex.ToString() End Try ' ***Set the CancellationTokenSource to null when the work is complete. cts = Nothing ' In case you want to try again. StartButton.IsEnabled = True End Sub ' Provide a parameter for the CancellationToken. Async Function DownloadBlogsAsync(ct As CancellationToken) As Task Dim client As Windows.Web.Syndication.SyndicationClient = New SyndicationClient() Dim uriList = CreateUriList() ' Force the SyndicationClient to download the information. client.BypassCacheOnRetrieve = True ' The following code avoids the use of implicit typing (var) so that you ' can identify the types clearly. For Each uri In uriList ' ***These three lines are combined in the single statement that follows them. 'Dim feedOp As IAsyncOperationWithProgress(Of SyndicationFeed, RetrievalProgress) = ' client.RetrieveFeedAsync(uri) 'Dim feedTask As Task(Of SyndicationFeed) = feedOp.AsTask(ct) 'Dim feed As SyndicationFeed = Await feedTask ' ***You can combine the previous three steps in one expression. Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(uri).AsTask(ct) DisplayResults(feed, ct) Next End Function ' ***Add an event handler for the Cancel button. Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs) If cts IsNot Nothing Then cts.Cancel() ResultsTextBox.Text &= vbCrLf & "Downloads canceled by the Cancel button." End If 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/business/atom.aspx"), New Uri("https://windowsteamblog.com/windows/b/windowsexperience/atom.aspx"), New Uri("https://windowsteamblog.com/windows/b/windowssecurity/atom.aspx"), New Uri("https://windowsteamblog.com/windows/b/windowshomeserver/atom.aspx"), New Uri("https://windowsteamblog.com/windows/b/springboard/atom.aspx") } Return uriList End Function ' You can pass the CancellationToken to this method if you think you might use a ' cancellable API here in the future. Sub DisplayResults(sf As SyndicationFeed, ct As CancellationToken) ' Title of the blog. ResultsTextBox.Text &= sf.Title.Text & vbCrLf ' Titles and dates for the first three blog posts. For i As Integer = 0 To If(sf.Items.Count >= 3, 2, sf.Items.Count) ResultsTextBox.Text &= vbTab & sf.Items.ElementAt(i).Title.Text & ", " & sf.Items.ElementAt(i).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 Tasks. using System.Threading.Tasks; // Add a using directive for CancellationToken. using System.Threading; namespace BlogFeedWithCancellation { public sealed partial class MainPage : Page { // ***Declare a System.Threading.CancellationTokenSource. CancellationTokenSource cts; public MainPage() { this.InitializeComponent(); } private async void StartButton_Click(object sender, RoutedEventArgs e) { ResultsTextBox.Text = ""; // Prevent unexpected reentrance. StartButton.IsEnabled = false; // ***Instantiate the CancellationTokenSource. cts = new CancellationTokenSource(); try { // ***Send a token to carry the message if cancellation is requested. await DownloadBlogsAsync(cts.Token); } // ***Check for cancellations. catch (OperationCanceledException) { // In practice, this catch block often is empty. It is used to absorb // the exception, ResultsTextBox.Text += "\r\nCancellation exception bubbles up to the caller."; } // Check for other exceptions. catch (Exception ex) { ResultsTextBox.Text = "Page could not be loaded.\r\n" + "Exception: " + ex.ToString(); } // ***Set the CancellationTokenSource to null when the work is complete. cts = null; // In case you want to try again. StartButton.IsEnabled = true; } // ***Provide a parameter for the CancellationToken. async Task DownloadBlogsAsync(CancellationToken ct) { Windows.Web.Syndication.SyndicationClient client = new SyndicationClient(); var uriList = CreateUriList(); // Force the SyndicationClient to download the information. client.BypassCacheOnRetrieve = true; // The following code avoids the use of implicit typing (var) so that you // can identify the types clearly. foreach (var uri in uriList) { // ***These three lines are combined in the single statement that follows them. //IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> feedOp = // client.RetrieveFeedAsync(uri); //Task<SyndicationFeed> feedTask = feedOp.AsTask(ct); //SyndicationFeed feed = await feedTask; // ***You can combine the previous three steps in one expression. SyndicationFeed feed = await client.RetrieveFeedAsync(uri).AsTask(ct); DisplayResults(feed); } } // ***Add an event handler for the Cancel button. private void CancelButton_Click(object sender, RoutedEventArgs e) { if (cts != null) { cts.Cancel(); ResultsTextBox.Text += "\r\nDownloads canceled by the Cancel button."; } } 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/business/atom.aspx"), new Uri("https://windowsteamblog.com/windows/b/windowsexperience/atom.aspx"), new Uri("https://windowsteamblog.com/windows/b/windowssecurity/atom.aspx"), new Uri("https://windowsteamblog.com/windows/b/windowshomeserver/atom.aspx"), new Uri("https://windowsteamblog.com/windows/b/springboard/atom.aspx") }; return uriList; } // You can pass the CancellationToken to this method if you think you might use a // cancellable API here in the future. void DisplayResults(SyndicationFeed sf) { // Title of the blog. ResultsTextBox.Text += sf.Title.Text + "\r\n"; // Titles and dates for the first three blog posts. for (int i = 0; i < (sf.Items.Count < 3 ? sf.Items.Count : 3); i++) // Is Math.Min better? { ResultsTextBox.Text += "\t" + sf.Items.ElementAt(i).Title.Text + ", " + sf.Items.ElementAt(i).PublishedDate.ToString() + "\r\n"; } ResultsTextBox.Text += "\r\n"; } } }
選取 F5 鍵執行程式,然後選取 [開始] 按鈕。
請參閱
概念
WhenAny:銜接 .NET Framework 和 Windows 執行階段 (C# 和 Visual Basic)
在一段時間後取消工作 (C# 和 Visual Basic)