So, I wanted to do asynchronously database search that could take a long time. But if the user refine her search criteria, the async should restart, and whatever already found records be disregarded.
Using the following Microsoft article as a template, this is what I came up with as a proof of concept.
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/cancel-an-async-task-or-a-list-of-tasks
This WPF program has 3 buttons.
Start - will cancel all already started jobs, waits for 5 sec. and then download some content from a msdn site.
Cancel All - will simply cancel all started jobs.
Clear - will cancel all started jobs, and clear any messages.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
// Add a using directive and a reference for System.Net.Http.
using System.Net.Http;
// Add the following using directive for System.Threading.
using System.Threading;
namespace CancelATask
{
public partial class MainWindow : Window
{
// ***Declare a System.Threading.CancellationTokenSource.
List<CancellationTokenSource> cts = new List<CancellationTokenSource>();
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
cts?.ForEach(c => c.Cancel());
// ***Instantiate the CancellationTokenSource.
using (CancellationTokenSource c = new CancellationTokenSource())
{
cts.Add(c);
try
{
// ***Send a token to carry the message if cancellation is requested.
int contentLength = await AccessTheWebAsync(c.Token);
resultsTextBox.Text += $"\r\nLength of the downloaded string: {contentLength}.\r\n";
}
// *** If cancellation is requested, an OperationCanceledException results.
catch (OperationCanceledException)
{
resultsTextBox.Text += $"\r\nDownload canceled. Current no of jobs: {cts.Count}\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownload failed.\r\n";
}
cts.Remove(c);
}
}
// ***Add an event handler for the Cancel button.
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
cts?.ForEach(c => c.Cancel());
}
private void clearButton_Click(object sender, RoutedEventArgs e)
{
cts?.ForEach(c => c.Cancel());
resultsTextBox.Clear();
}
// ***Provide a parameter for the CancellationToken.
async Task<int> AccessTheWebAsync(CancellationToken c)
{
HttpClient client = new HttpClient();
resultsTextBox.Text += "Waiting for download to commence.\r\n";
// You might need to slow things down to have a chance to cancel.
await Task.Delay(5000, c);
resultsTextBox.Text += "Commencing to download.\r\n";
// GetAsync returns a Task<HttpResponseMessage>.
// ***The c argument carries the message if the Cancel button is chosen.
HttpResponseMessage response = await client.GetAsync("http://msdn.microsoft.com/en-us/library/dd470362.aspx", c);
// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
// The result of the method is the length of the downloaded web site.
return urlContents.Length;
}
}
// Output for a successful download:
// Ready to download.
// Length of the downloaded string: 158125.
// Or, if you cancel:
// Ready to download.
// Download canceled.
}
As always feel free to ask or comment.