Let's say I have a simple UWP app (so no .NET 5 or C# 8 without workarounds irrelevant to this situation), with many pages that contain buttons, all of which must be able to start work by calling SeriousWorkAsync
and FunWorkAsync
:
public async Task SeriousWorkAsync(SeriousObject obj)
{
Setup(obj);
for (int i = 0; i < 10000; i++)
{
await SeriousThingAsync(i);
}
}
public async Task FunWorkAsync(FunObject obj)
{
Setup(obj);
for (int i = 0; i < 10000; i++)
{
await FunnyThingAsync(i);
}
}
My requirements are as follows:
- None of the buttons can be disabled at any point.
- No tasks should ever run concurrently.
- Whenever I call
SeriousWorkAsync
, I wantFunWorkAsync
to finish execution, and after cancellation is complete,SeriousWorkAsync
should start. - Likewise, if I call
SeriousWorkAsync
while another call toSeriousWorkAsync
is executing, I have to cancel that another call, and the newer call should only do stuff after cancellation is complete. - If there's any extra calls, the first call should cancel first, and only the last call should execute.
So far, the best solution I could come up with is delaying the Task in a loop until the other one's cancelled, with a few boolean flags that are set as soon as the method finishes execution:
private bool IsDoingWork = false;
private bool ShouldCancel = false;
public async Task FunWorkAsync(FunObject obj)
{
CancelPendingWork();
while (IsDoingWork)
{
await Task.Delay(30);
}
IsDoingWork = true;
Setup(obj);
for (int i = 0; i < 10000; i++)
{
if (ShouldCancel)
{
break;
}
await FunnyThingAsync(i);
}
IsDoingWork = false;
}
private void CancelPendingWork()
{
if (IsDoingWork)
{
ShouldCancel = true;
}
}
However, this feels like a very dirty workaround, and it doesn't address my last requirement. I know I should use CancellationToken, but my attempts at using it have been unsuccessful so far, even after a lot of searching and brainstorming. So, how should I go about this?