Cancelación: Puente entre .NET Framework y Windows en tiempo de ejecución (C# y Visual Basic)

Puede optimizar los recursos combinando las funciones de .NET Framework y de Windows en tiempo de ejecución.El ejemplo de este tema se muestra cómo utilizar una instancia de .NET FrameworkCancellationToken para agregar un botón de cancelación a una aplicación que utiliza un método de Windows en tiempo de ejecución para descargar blogs de web.

[!NOTA]

Para ejecutar el ejemplo, debe tener Windows 8 instalado en el equipo.Además, si desea ejecutar el ejemplo desde Visual Studio, también debe tener Visual Studio 2012 o Visual Studio Express 2012 para Windows 8 instalado.

AsTask proporciona un puente

El token de cancelación requiere las instancias de Task, pero el método de Windows en tiempo de ejecución genera IAsyncOperationWithProgress instancias.Puede utilizar el método de extensión de AsTask en .NET Framework unir entre ellas.

El método de DownloadBlogsAsync en el ejemplo hace la mayor parte del trabajo.

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

La sección comentada - out en el bucle muestra los pasos de transición en detalle.

  • La llamada SyndicationClient.RetrieveFeedAsync al iniciar una operación asincrónica que descarga una fuente de blog de un URI especificado.La operación asincrónica es IAsyncOperationWithProgress una instancia.

    Dim feedOp As IAsyncOperationWithProgress(Of SyndicationFeed, RetrievalProgress) = 
        client.RetrieveFeedAsync(uri)
    
    IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> feedOp =  
        client.RetrieveFeedAsync(uri);
    
  • Dado que las capacidades de cancelación en .NET Framework que desea utilizar requieren tareas, el código aplica AsTask para representar la instancia de IAsyncOperationWithProgress como Task<TResult>.En particular, el código aplica una sobrecarga de AsTask que acepta un argumento de CancellationToken.

    Dim feedTask As Task(Of SyndicationFeed) = feedOp.AsTask(ct)
    
    Task<SyndicationFeed> feedTask = feedOp.AsTask(ct);
    
  • Finalmente, await o el operador de Await espera la tarea de recuperar SyndicationFeed el resultado.

    Dim feed As SyndicationFeed = Await feedTask
    
    SyndicationFeed feed = await feedTask;
    

Para obtener más información sobre AsTask, vea Extender el código de Starter en WhenAny: Puente entre .NET Framework y Windows en tiempo de ejecución (C# y Visual Basic).

Puntos de interés

Puede revisar el ejemplo completo adoptando el final de este tema, descargar el ejemplo en el equipo local, o compilar el ejemplo.Para obtener más información e instrucciones, vea Configurar el ejemplo.

Cuando revise el ejemplo, verá los asteriscos que presentan los puntos importantes.Se recomienda leer esta sección para entender mejor estos puntos, especialmente si no ha utilizado CancellationToken antes.

Para implementar un botón de cancelación, el código debe incluir los elementos siguientes.

  • Una variable de CancellationTokenSource, cts, que está en el ámbito de todos los métodos que tengan acceso.

    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;
    
  • Un controlador de eventos para el botón cancelar.El controlador de eventos utiliza el método CancellationTokenSource.Cancel para notificar cts cuando el usuario solicita la cancelación.

    ' ***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.";
        }
    }
    
  • Un controlador de eventos para el botón Inicio, StartButton_Click, que incluye las siguientes acciones.

    • El controlador de eventos crea instancias CancellationTokenSource, cts.

      cts = New CancellationTokenSource()
      
      // ***Instantiate the CancellationTokenSource.
      cts = new CancellationTokenSource();
      
    • En la llamada a DownloadBlogsAsync, que descarga blogs, el código envía la propiedad de CancellationTokenSource.Token de cts como argumento.La propiedad Token propaga el mensaje si se solicita la cancelación.

      Await DownloadBlogsAsync(cts.Token)
      
      await DownloadBlogsAsync(cts.Token);
      
    • La llamada a DownloadBlogsAsync contenida en una instrucción de try-catch que incluya una captura bloqueado para OperationCanceledException cuyo resultado cuando elija el botón cancelar.El llamador del método async define qué acción para tomar.Este ejemplo sólo muestra un mensaje.

      El código siguiente se muestra la instrucción completa de la intento- captura.

      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();
      }
      
  • Como se ha descrito anteriormente en este tema, las llamadas al método de DownloadBlogsAsync el método de Windows en tiempo de ejecución, RetrieveFeedAsync, y se aplica un método de extensión de .NET Framework, AsTask, a la instancia devuelta de IAsyncOperation.AsTask representa la instancia como Task, para poder enviar el token de cancelación a la operación asincrónica.El token lleva el mensaje cuando elija el botón cancelar.

    Observe que el uso AsTask, el código puede pasar la misma instancia de CancellationToken a un método de Windows en tiempo de ejecución (RetrieveFeedAsync) y un método de .NET Framework (DownloadBlogsAsync).

    La siguiente línea muestra esta parte del código.

    Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(uri).AsTask(ct)
    
    SyndicationFeed feed = await client.RetrieveFeedAsync(uri).AsTask(ct);
    
  • Si no cancela la aplicación, genera el siguiente resultado.

    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
    

    Si elige el botón cancelar antes de que la aplicación finalice de descargar el contenido, el resultado se parece al siguiente resultado.

    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.
    

Configurar el ejemplo

Puede descargar la aplicación, compilarlo personalmente, o revisar el código al final de este tema sin implementarlo.Visual Studio 2012 y Windows 8 debe instalarse en el equipo para ejecutar esta aplicación.

Para descargar la aplicación finalizada

  1. Descargue el archivo comprimido de Ejemplo Async: Puente entre .NET y el tiempo de ejecución de Windows (AsTask y Cancelación).

  2. Descomprima el archivo que ha descargado, y inicia Visual Studio.

  3. En la barra de menú, elija Archivo, Abrir, Proyecto/Solución.

  4. Navegue a la carpeta que contiene el código de ejemplo descomprimido, y vuelva a abrir el archivo de solución (.sln).

  5. Elija la tecla F5 para compilar y ejecutar el proyecto.

    Ejecute el código varias veces para comprobar que puede cancelar en momentos diferentes.

Para compilar la aplicación finalizada

  1. Inicie Visual Studio.

  2. En la barra de menú, elija Archivo, Nuevo, Proyecto.

    Aparece el cuadro de diálogo Nuevo proyecto.

  3. En Instalado, categoría Plantillas, elija Visual Basic o en Visual c# y, a continuación Tienda Windows.

  4. En la lista de tipos de proyecto, elija Aplicación en blanco (XAML).

  5. Asigne al proyecto BlogFeedWithCancellation, y elija el botón Aceptar.

    El nuevo proyecto aparecerá en el Explorador de soluciones.

  6. En Explorador de soluciones, abra el menú contextual para MainPage.xaml y, a continuación Abrir.

  7. En la ventana XAML de MainPage.xaml, reemplace el código por el código siguiente.

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

    Una ventana simple que contiene un cuadro de texto, una clave inicial, y un botón cancelar aparece en la ventana Diseñar de MainPage.xaml.

  8. En Explorador de soluciones, abra el menú contextual para MainPage.xaml.vb o MainPage.xaml.cs y, a continuación ver código.

  9. Reemplace el código de MainPage.xaml.vb o MainPage.xaml.cs con el código siguiente.

    ' 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. Presione la tecla F5 para ejecutar el programa y, a continuación, elija el botón Iniciar.

Vea también

Conceptos

WhenAny: Puente entre .NET Framework y Windows en tiempo de ejecución (C# y Visual Basic)

Cancelar una tarea o lista de tareas (C# y Visual Basic)

Cancelar tareas tras un período de tiempo (C# y Visual Basic)

Cancelar las tareas restantes cuando se completa una (C# y Visual Basic)

Tokens de cancelación