Since I've discussed Asynchronous processing on past blogs, I've gotten a few questions about how to cancel an asynchronous process. I figure I should blog my response, and while I'm at it, include most of the Async stuff into a single unified example; providing a .Net Kitchen “Sync“ (I know Darrell really appreciates these puns).
Using the techniques discussed in my post here (http://dotnetjunkies.com/weblog/grant.killian/posts/1805.aspx) and earlier, we can add a "Cancel" feature to our example without too much trouble.
For this example, I place two button controls and a progressbar on a form (leaving the default names for simplicity); one button will launch our asynchronous work, the other button will cancel it. We need to extend our StatusEventArgs class to include a boolean indicator for when the user cancels the async work, something like:
public bool isStopped;
Of course a public property is better technique, but not as terse for an example.
Next, we can add a public boolean variable to the winform; when button2 is clicked, we set this variable to true:
public bool _blnIsStopped;
private void button2_Click(object sender, System.EventArgs e)
{
_blnStopped = true;
}
Next, we need to build in the logic to stop asynchronous processing based on this _blnStopped flag (this is in the winForm app and handles updates broadcast by the asynchronous work):
void ShowProgress( object sender, StatusEventArgs e)
{
if( this.InvokeRequired == false )
{
ShowProgressHandler showProgress =
new ShowProgressHandler( ShowProgress );
Invoke( showProgress, new object[] { sender, e } );
}
else
{
e.isStopped=_blnStopped;
}
}
By setting the isStopped flag to true in the synchronous ShowProgress method, thanks to the reference variable StatusEventArgs, we can communicate the "cancel" request to the asynchronous processing. To complete the coding, we just need something like the following:
if( !e.isStopped ) { //check to see if the user stopped the processing
//do time consuming work
ShowProgress( sender, e ); //call to win app
} else {
//the user stopped the processing . . .
break;
}
As promised, here is a unified example showing asynchronous processing with exception handling, status updates to the client application, and support for cancellation of the async work from the client app:
//WinForm code:
public delegate void ShowProgressHandler(object sender, StatusEventArgs e);
public delegate void ClientShowProgressDelegate( showProgressDelegate del );
public bool _blnStopped = false;
private void button1_Click(object sender, System.EventArgs e)
{
showProgressDelegate del =
new showProgressDelegate( ShowProgress );
util obj = new util();
ClientShowProgressDelegate cliDel =
new ClientShowProgressDelegate( obj.populateProducts );
cliDel.BeginInvoke( del, null, null );
}
void ShowProgress( object sender, StatusEventArgs e)
{
if( this.InvokeRequired == false )
{
ShowProgressHandler showProgress =
new ShowProgressHandler( ShowProgress );
Invoke( showProgress, new object[] { sender, e } );
}
else
{
if( object.ReferenceEquals( e.TheException, null ) ) {
progressBar1.Maximum = e.TotalProgress;
progressBar1.Value = e.ProgressSoFar;
if( e.isComplete )
{
MessageBox.Show( "Finished" );
}
e.isStopped=_blnStopped;
}else {
MessageBox.Show( "Exception thrown: " + e.TheException.ToString() );
progressBar1.Value = 0;
}
}
}
private void button2_Click(object sender, System.EventArgs e)
{
_blnStopped = true;
}
//Our async code in the same namespace:
public delegate void showProgressDelegate( object sender, StatusEventArgs e );
public class util{
public void populateProducts( showProgressDelegate ShowProgress )
{
StatusEventArgs e = new StatusEventArgs( 10, 0 );
object sender = new object();
try{
ShowProgress( sender, e ); //call to win app
for( int x = 0; x < 10; x++ )
{
if( !e.isStopped ) {
System.Threading.Thread.Sleep( 5000 );
e.ProgressSoFar+=1;
ShowProgress( sender, e ); //call to win app
} else {
//the user stopped the processing . . .
e.ProgressSoFar=0;
break;
}
}
if( !e.isStopped ) {
e.isComplete = true;
}
ShowProgress(sender, e); //final call to win ap
} catch( Exception ex ) {
e.TheException = ex;
ShowProgress( sender, e );
}
}
}
public class StatusEventArgs : EventArgs
{
public bool isComplete;
public int TotalProgress;
public int ProgressSoFar;
public Exception TheException;
public bool isStopped;
public StatusEventArgs( int totalProgress, int progressSoFar )
{
this.isStopped = false;
this.isComplete = false;
this.TotalProgress = totalProgress;
this.ProgressSoFar = progressSoFar;
}
}
This concludes the async portion of this weblog (probably, but I wouldn't underestimate my ability to beat a dead horse -- just ask a few students!).
Happy .Netting!