I have a button in WinForms which imports from a text file. Once it starts importing, it changes the text of the button to Processing...
and instantiates a CancellationToken which is supposed to cancel the operation if the user requests. If the button is pressed again while it's still importing, it should activate the task cancellation.
There are many ways to do that and I can't decide which one to use. What is the cleanest way?
private CancellationTokenSource _cts;
private List<string> _list = new List<string>();
private async void Button_Click(object sender, EventArgs e)
{
if (button.Text == "Processing...")
{
if (_cts != null)
{
_cts.Cancel();
_cts.Dispose();
}
}
else
{
using var dialog = new OpenFileDialog
{
Filter = "All Files (*.*)|*.*"
};
if (dialog.ShowDialog() == DialogResult.OK)
{
button.Text = "Processing...";
_cts = new CancellationTokenSource();
var fileStream = dialog.OpenFile();
using var reader = new StreamReader(fileStream);
try
{
int count = 0;
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync().WithCancellation(_cts.Token).ConfigureAwait(false);
Trace.WriteLine(line);
_list.Add(line);
count++;
}
}
catch (TaskCanceledException)
{
}
//await Task.Run(async () =>
//{
// int count = 0;
// while (!reader.EndOfStream)
// {
// var line = await reader.ReadLineAsync().ConfigureAwait(false);
// //var line = reader.ReadLine();
// Trace.WriteLine(line);
// count++;
// }
//});
//await Task.Factory.StartNew(() =>
//{
// int count = 0;
// while (!reader.EndOfStream)
// {
// var line = reader.ReadLine();
// Trace.WriteLine(line);
// count++;
// }
//});
BeginInvoke(new Action(() => button.Text = "Process"));
}
}
}
public static class ThreadExtensionMethods
{
public static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
return task.IsCompleted // fast-path optimization
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
}