非同期のキャンセル: .NET Framework と Windows ランタイム間のブリッジ (C# および Visual Basic)

.NET Framework と Windows ランタイム の機能を組み合わせることによって、リソースを最大化できます。 このトピックの例では、.NET Framework CancellationToken インスタンスを使用して、Windows ランタイム メソッドを使って Web からブログ フィードをダウンロードするアプリケーションにキャンセル ボタンを追加する方法を示します。

注意

例を実行するには、Windows 8 がコンピューターにインストールされている必要があります。Visual Studio から例を実行するには、Visual Studio 2012、Visual Studio 2013、Visual Studio Express 2012 for Windows 8、または Visual Studio Express 2013 for Windows もインストールされている必要があります。

AsTask による橋渡し

キャンセル トークンは Task インスタンスを必要としますが、Windows ランタイム メソッドは IAsyncOperationWithProgress インスタンスを生成します。 .NET Framework の AsTask``2 拡張メソッドを使って、それらの間をブリッジできます。

この例の 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``1 を適用して IAsyncOperationWithProgress インスタンスを Task として表します。 特に、コードは 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 の呼び出しでは、コードは引数として cts の CancellationTokenSource.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 を呼び出し、返された IAsyncOperation インスタンスに .NET Framework 拡張メソッドの AsTask を適用します。 AsTask はインスタンスを Task として表すため、キャンセル トークンを非同期操作に送信できます。 キャンセル ボタンをクリックすると、トークンがメッセージを送信します。

    AsTask を使用すると、コードは Windows ランタイム メソッド (RetrieveFeedAsync) および .NET Framework メソッド (DownloadBlogsAsync) の両方に CancellationToken の同じインスタンスを渡すことができることに注意してください。

    次の行はコードのこの部分を示しています。

    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 および Windows 8 がインストールされている必要があります。

完成したアプリをダウンロードするには

  1. 圧縮ファイルは「Async Sample: Bridging between .NET and Windows Runtime (AsTask & Cancellation) (非同期のサンプル: .NET と Windows ランタイム間のブリッジ (AsTask と Cancellation))」からダウンロードできます。

  2. ダウンロードしたファイルを圧縮解除し、Visual Studio を起動します。

  3. メニュー バーで [ファイル][開く][プロジェクト/ソリューション] の順に選択します。

  4. 圧縮解除したサンプル コードが含まれるフォルダーに移動し、ソリューション (.sln) ファイルを開きます。

  5. F5 キーを押してプロジェクトをビルドし、実行します。

    コードを複数回実行して、さまざまな時点で取り消しできることを確認します。

完成したアプリケーションをビルドするには

  1. Visual Studio を起動します。

  2. メニュー バーで [ファイル][新規][プロジェクト] の順にクリックします。

    [新しいプロジェクト] ダイアログ ボックスが表示されます。

  3. [インストール済み][テンプレート] カテゴリ、[Visual Basic] または [Visual C#][Windows ストア] の順に選択します。

  4. プロジェクトの種類の一覧から [新しいアプリケーション (XAML)] をクリックします。

  5. プロジェクトに「BlogFeedWithCancellation」という名前を付け、[OK] をクリックします。

    ソリューション エクスプローラーに新しいプロジェクトが表示されます。

  6. [ソリューション エクスプローラー]で、MainPage.xaml のショートカット メニューを開き、[開く] をクリックします。

  7. MainPage.xaml の [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 のデザイン ウィンドウに表示されます。

  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 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";
            }
        }
    }
    
  10. F5 キーを押してプログラムを実行し、[Start] を複数回クリックします。

参照

概念

WhenAny: .NET Framework と Windows ランタイム間のブリッジ (C# および Visual Basic)

非同期タスクまたはタスクの一覧のキャンセル (C# および Visual Basic)

指定した時間の経過後の非同期タスクのキャンセル (C# および Visual Basic)

完了後の残りの非同期タスクのキャンセル (C# および Visual Basic)

キャンセル トークン