views:

413

answers:

3

I have the following delegate

delegate void UpdateFileDelegate(long maxFileID);

That I am calling from a WinForms app like so

UpdateFileDelegate FD = new UpdateFileDelegate(ClassInstance.UpdateFile);
FD.BeginInvoke(longIDNumber,null,null);

It runs asynchronously but the question I have is how can I tell when the Method is done executing so I can let the end user know?

Update: Thanks to the recommendations below the following code does the trick. Also this article was helpful in getting me to understand what my code is actually doing.

delegate void UpdateFileDelegate(long maxFileID);
UpdateFileDelegate FB = new UpdateFileDelegate(ClassInstance.UpdateFile);
AsyncCallback callback = new AsyncCallback(this.CallBackMethod);
IAsyncResult result = FB.BeginInvoke(longIDNumber);

private void CallBackMethod(IAsyncResult result)
    {
     AsyncResult delegateResult = (AsyncResult)result;

     UpdateFileDelegate fd = (UpdateFileDelegate)delegateResult.AsyncDelegate;
     fd.EndInvoke(result);
     MessageBox.Show("All Done!");
    }
+5  A: 

See Calling Synchronous Methods Asynchronously

The BeginInvoke will return an IAsyncResult, which enables a number of different ways to be aware of when it is done, such as using its AsyncWaitHandle.WaitOne() method. It depends on what you are doing in the meantime.

Or you can pass a delegate for a callback method to BeginInvoke. This is arguably the most powerful strategy, but sometimes is overkill.

Dave
A: 

Write another method say UpdateFileAndNotifyUser

void UpdateFileAndNotifyUser(long id, object arg1, object arg2)
{
       ClassInstance.UpdateFile(id, arg1, arg2);
       NotifyUserThatTheOperationIsDone();
}

var FD = new UpdateFileDelegate(UpdateFileAndNotifyUser);
FD.BeginInvoke(longIDNumber,null,null);
Hasan Khan
However, you may run into some cross-threading issues with a solution like this. That would have to be handled in NotifyUserThatTheOperationIsDone or somewhere downstream.
Dave
Dave is right, the callback will be called in the thread where the async method is called. If you're running in Windows Forms, you'll have to use a WindowsFormsSynchronizationContext to get back to the initial (UI) thread.
Yann Schwartz
@Dave: when using `BeginInvoke` on a delegate, you run into exact same problem - the callback is also called on the (background) thread on which the delegate was invoked.
Pavel Minaev
@Pavel: +1 Absolutely; good information for the user to know. I was thinking more the simpler WaitOne() cases or things like that.
Dave
+4  A: 

Calling EndInvoke on the returned IAsyncResult reference is very important. It is the only way to find out if the delegate target finished executing without any exceptions. If you don't, such an exception will fall into the bit-bucket and your program will silently fail to execute properly. You can call EndInvoke either on the same thread that called BeginInvoke() or you can do it in a callback. Calling it on the same thread rarely is useful, you'd almost always lose the benefits of asynchronous execution. Some sample code that demonstrates both and emphasizes the exception handling:

using System;
using System.Runtime.Remoting.Messaging;

class Program {
  static void Main(string[] args) {
    new Program().Run();
    Console.ReadLine();
  }
  void Run() {
    Action example = new Action(threaded);
    IAsyncResult ia = example.BeginInvoke(new AsyncCallback(completed), null);
    // Option #1:
    /*
    ia.AsyncWaitHandle.WaitOne();
    try {
      example.EndInvoke(ia);
    }
    catch (ApplicationException ex) {
      Console.WriteLine(ex.Message);
    }
    */
  }

  void threaded() {
    throw new ApplicationException("Kaboom");
  }

  void completed(IAsyncResult ar) {
    // Option #2:
    Action example = (ar as AsyncResult).AsyncDelegate as Action;
    try {
      example.EndInvoke(ar);
    }
    catch (ApplicationException ex) {
      Console.WriteLine(ex.Message);
    }
  }
}

You should not use a try block in the completion callback if you don't expect the code to throw exceptions. This ensures your program terminates when it does.

Hans Passant