Cancelamento: ponte entre o .NET Framework e o Tempo de Execução do Windows (C# e Visual Basic)
Você pode maximizar seus recursos combinando os recursos do.NET Framework e de Tempo de Execução do Windows.O exemplo neste tópico mostra como usar uma instância de .NET FrameworkCancellationToken para adicionar um botão cancelar a um aplicativo que usa um método de Tempo de Execução do Windows para baixar feeds do blog da Web.
Observação |
---|
Para executar o exemplo, você deve ter o Windows 8 instalado no seu computador.Além disso, se deseja executar o exemplo do Visual Studio, também deverá ter o Visual Studio 2012 ou o Visual Studio Express 2012 for Windows 8 instalado. |
AsTask fornece uma ponte
O token cancelar requer instâncias de Task , mas o método de Tempo de Execução do Windows gera IAsyncOperationWithProgress instâncias.Você pode usar o método de extensão de AsTask no .NET Framework para ponte entre entre eles.
O método de DownloadBlogsAsync no exemplo faz a maioria de trabalho.
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);
}
}
A seção comentada - para fora do loop mostra as etapas de transição em detalhes.
A chamada SyndicationClient.RetrieveFeedAsync para iniciar uma operação assíncrona que baixa um avanço do blog URI especificado.A operação assíncrona é IAsyncOperationWithProgress uma instância.
Dim feedOp As IAsyncOperationWithProgress(Of SyndicationFeed, RetrievalProgress) = client.RetrieveFeedAsync(uri)
IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> feedOp = client.RetrieveFeedAsync(uri);
Porque os recursos cancelar no .NET Framework que você deseja usar exigem tarefas, o código aplica o AsTask para representar a instância de IAsyncOperationWithProgress como Task<TResult>.Em particular, o código aplica uma sobrecarga de AsTask que aceita um argumento de CancellationToken .
Dim feedTask As Task(Of SyndicationFeed) = feedOp.AsTask(ct)
Task<SyndicationFeed> feedTask = feedOp.AsTask(ct);
Finalmente, await ou o operador de Await esperam a tarefa recuperar SyndicationFeed o resultado.
Dim feed As SyndicationFeed = Await feedTask
SyndicationFeed feed = await feedTask;
Para obter mais informações sobre a AsTask, consulte Estendendo o código de iniciantes em WhenAny: ponte entre o .NET Framework e o Tempo de Execução do Windows (C# e Visual Basic).
Pontos de interesse
Você pode examinar o exemplo inteiro enrolando ao final deste tópico, fazendo o exemplo para seu computador local, ou compilar o exemplo.Para mais informações e instruções, consulte Configurando o exemplo.
Porque você examina o exemplo, você notará que os asteriscos realçam pontos importantes.É recomendável que você leia esta seção para compreender melhor esses pontos, especialmente se você não tiver usado CancellationToken antes.
Para implementar um botão cancelar, seu código deve incluir os seguintes elementos.
Uma variável de CancellationTokenSource , cts, que está no escopo para todos os métodos que o acesso.
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;
Um manipulador de eventos para o botão de Cancelar .O manipulador de eventos usar o método de CancellationTokenSource.Cancel para notificar cts quando cancelamento de um usuário.
' ***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."; } }
Um manipulador de eventos para o botão de Iniciar , StartButton_Click, que inclui as seguintes ações.
O manipulador de eventos cria uma instância CancellationTokenSource, cts.
cts = New CancellationTokenSource()
// ***Instantiate the CancellationTokenSource. cts = new CancellationTokenSource();
Na chamada a DownloadBlogsAsync, que baixa os feeds do blog, o código envia a propriedade de CancellationTokenSource.Token de cts como um argumento.A propriedade de Token propaga a mensagem se o cancelar for solicitado.
Await DownloadBlogsAsync(cts.Token)
await DownloadBlogsAsync(cts.Token);
A chamada a DownloadBlogsAsync é abrigado em uma instrução de try-catch que inclui um bloco catch para OperationCanceledException que resulte quando você escolhe o botão de Cancelar .O chamador do método de async que define tomar ação.Este exemplo exibe apenas uma mensagem.
O código a seguir mostra a declaração completa 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(); }
Como descrito anteriormente neste tópico, o método de DownloadBlogsAsync chama o método de Tempo de Execução do Windows , RetrieveFeedAsync, e aplicar um método de extensão de .NET Framework , AsTask, a instância retornado de IAsyncOperation .AsTask representa a instância como Task, para que você possa enviar o símbolo cancelar a operação assíncrona.O token leva a mensagem quando você escolhe o botão de Cancelar .
Observe que usando AsTask, o código pode passar a mesma instância de CancellationToken para um método de Tempo de Execução do Windows (RetrieveFeedAsync) e um método de .NET Framework (DownloadBlogsAsync).
A linha a seguir mostra essa parte do código.
Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(uri).AsTask(ct)
SyndicationFeed feed = await client.RetrieveFeedAsync(uri).AsTask(ct);
Se você desfizer o aplicativo, produz a seguinte saída.
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
Se você escolher o botão de Cancelar antes que o aplicativo seja concluído baixar conteúdo, o resultado é semelhante a seguinte saída.
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.
Configurando o exemplo
Você pode baixar o aplicativo, compilá-lo você mesmo, ou examinar o código no final deste tópico não implementa.O Visual Studio 2012 e Windows 8 devem ser instalados no seu computador para executar este aplicativo.
Para baixar o aplicativo concluído
Baixar o arquivo compactado de Exemplo de Async: Compilação de uma ponte entre sobre .NET e Tempo de Execução do Windows (AsTask e cancelar).
Descompactar o arquivo que você baixou, e comece em Visual Studio.
Na barra de menu, escolha Arquivo, Abrir, Projeto/solução.
Navegue até a pasta que contém o código de exemplo descompactado, e abra o arquivo de solução (.sln).
Escolha a tecla F5 para compilar e executar o projeto.
Executar o código várias vezes verifique que você pode cancelar em pontos diferentes.
Para compilar o aplicativo concluído
Inicie o Visual Studio.
Na barra de menu, escolha Arquivo, Novo, Projeto.
A Caixa de diálogo Novo Projeto é exibida.
Em Instalado, a categoria de Modelos , escolha Visual Basic ou Visual C#, e então escolha Windows Store.
Da lista de tipos de projeto, escolha Aplicativo em branco (XAML).
Nomeie o projeto BlogFeedWithCancellation, escolha o botão de OK .
O novo projeto aparece no Gerenciador de Soluções.
Em Gerenciador de Soluções, abra o menu de atalho para MainPage.xaml, escolha Abrir.
Na janela de XAML de MainPage.xaml, substitua o código com o código a seguir.
<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>
Uma janela simples que contém uma caixa de texto, uma botão start, e um botão cancelar aparecem na janela de Design de MainPage.xaml.
Em Gerenciador de Soluções, abra o menu de atalho para MainPage.xaml.vb ou MainPage.xaml.cs, escolha Exibir Código.
Substitua o código em MainPage.xaml.vb ou em MainPage.xaml.cs com o código a seguir.
' 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"; } } }
Escolha a tecla F5 para executar o programa, escolha o botão de Iniciar .
Consulte também
Conceitos
WhenAny: ponte entre o .NET Framework e o Tempo de Execução do Windows (C# e Visual Basic)
Cancelar uma tarefa ou uma lista de tarefas (C# e Visual Basic)
Cancelar tarefas após um período (C# e Visual Basic)
Cancelar as demais tarefas depois que uma delas estiver concluída (C# e Visual Basic)