Reputation: 226
I'm a quite inexperienced c# programmer and need help on managing the flow of my program. It is a WinFormApp that asks for multiple user inputs and then uses them to establish serial communication with a device in order to make measurements. The measurements are made in an async method that takes about 20 minutes to run. So I'm using
void main()
{
//Setup
}
private void button1_Click(object sender, EventArgs e)
{
await measurements();
//Plot results
}
private async Task measurements()
{
while(true){
//Make some measurements
await Task.Delay(120000);
//Make measurements, present data in the UI form.
//return if done
}
}
Now I need to make a button which enables the user to cancel the measurements in order to change some input or parameter and then restart the measurements. So I added a "Cancel"-button.
private void button7_Click(object sender, EventArgs e)
{
textBox64.Enabled = true;
button6.Enabled = true;
button5.Enabled = true;
textBox63.Enabled = true;
button3.Enabled = true;
trackBar1.Enabled = true;
timer.Enabled = true;
button7.Enabled = false;
clearData();
// measurement.Stop();
}
Now I do not know how to manage the flow of the program. I have tried to make a try-catch
structure in button1_Click()
and throw an Exception from button7_Click
, but it doesn't get through to button1_Click()
.
Then I tried to run measurements()
on a new thread. But the thread does not have access to 70-ish UI items on my main form.
And even I wont sink as low as trying Goto.
What I need is advice on how you would program in this situation in order to get a good control of the application and not compromise the flow of the program with risky stuff like exceptions and Goto.
Upvotes: 8
Views: 4917
Reputation:
This is some rough code, but it should do the trick.
Using CancellationToken. I've used a toggle method to test if the async task is to be cancelled.
CancellationTokenSource cts;
private async button1_Click(object sender, EventArgs e)
{
toggleAsyncTask(false)
}
private void toggleAsyncTask(bool isCancelled)
{
if(cts==null)
var cts = new CancellationTokenSource();
if(!isCancelled)
{
await measurements(cts.Token);
}
else
{
cts.Cancel();
cts.Dispose();
cts = null;
}
}
private async Task measurementsOne(CancellationToken token)
{
try
{
while(true){
//Make some measurements
await Task.Delay(120000); // don't know if you need this.
//Make measurements, present data in the UI form.
//return if done
}
catch(OperationCancelledException)
{
// to do if you please.
}
}
private void button7_Click(object sender, EventArgs e)
{
// button stuff
toggleAsyncTask(true); // isCancelled is true.
}
Upvotes: 2
Reputation: 30493
If you want to cancel the actual task midway through then you need to look at using a CancellationTokenSource and passing a cancellation token into your async method.
This is the Microsoft documentation on that which has a good example near the bottom and this is another good blog on showing a progress bar and allowing cancellation. that second article has a good overview:
Cancellation is controlled by the CancellationToken structure. You expose cancellation tokens in the signature of cancelable async methods, enabling them to be shared between the task and caller. In the most common case, cancellation follows this flow:
- The caller creates a CancellationTokenSource object.
- The caller calls a cancelable async API, and passes the CancellationToken from the CancellationTokenSource (CancellationTokenSource.Token).
- The caller requests cancellation using the CancellationTokenSource object (CancellationTokenSource.Cancel()).
- The task acknowledges the cancellation and cancels itself, typically using the CancellationToken.ThrowIfCancellationRequested method.
To make your app respond quickly to a cancel request you need to then check the cancellation token regularly in your long running method and respond to it accordingly if a cancellation has been requested.
Upvotes: 6