I don't fully understand cancellation tokens, but I believe that is what I need to use.
I have a listbox full of file paths, and a method (ProcesstListSort
) which goes through each file path in the list box and executes different methods based on file type. ProcessListSort
is called from another method, that is called from a button click. I'm trying to run BeginEverything
in a background task because it was locking up the UI. What is the best place to implement cancellation token checking in this scenario?
This button click starts the process:
public async void button1_Click(object sender, EventArgs e)
{
Task task1 = new Task(BeginEverything);
task1.Start();
await task1;
}
Which launches this:
public void BeginEverything()
{
CreateThing1();
CreateThing2();
ProcessListSort(); //This is the one I think I need to interrupt because it's the longest
CreateThing3();
CreateThing4();
}
Which launches the longest task here (sorting files and executing other methods based on file type, passing the file path to those other methods):
public void ProcessListSort()
{
for (int i = 0; i < listBox2.Items.Count; i++)
{
string p = listBox2.Items[i].ToString();
FileAttributes attr = File.GetAttributes(p);
if (p.EndsWith(".zip"))
{
Method1(p);
}
if (p.EndsWith(".txt"))
{
Method2(p);
}
if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
{
Method3(p);
}
else
{
Method4(p);
}
}
}
Immediate cancellation after clicking a Cancel button would be ideal, but I would settle for just cancelling between each file that is processed in ProcessedListSort
. I think the problem is I am running methods from other methods and I'm not sure were the cancellation check needs to be applied. The closest I have gotten was where it saw the cancellation token, but only "cancelled" after everything had already executed.
Any other suggestions or links to alternate ways of doing this are greatly appreciated. I know I'm doing plenty of things incorrectly.
You'll have to create a CancellationTokenSource
and then pass the CancellationToken
to the methods you want to cancel.
private CancellationTokenSource _cts =
new CancellationTokenSource( );
public async void OnClick( object sender, EventArgs args )
{
// Disable your button here.
var token = _cts.Token;
try { await Task.Run( ( ) => LongRunning( token ), token ); }
catch( OperationCanceledException )
{
Console.WriteLine( "Task was cancelled" );
}
// Enable your button here.
}
public void OnCancel( object sender, EventArgs args )
{
_cts.Cancel( );
_cts.Dispose( );
_cts = new CancellationTokenSource( );
}
public void LongRunning( CancellationToken token = default )
{
// You can either check for cancellation
// or throw if cancelled.
// If cancellation is requested this will throw an
// OperationCanceledException.
token.ThrowIfCancellationRequested( );
// If you don't want to throw you can check the
// CancellationToken to see if cancellation was requested.
if ( token.IsCancellationRequested )
return;
// You can also pass the token to other methods that
// you want to observe cancellation.
AnotherLongRunning( token );
}