Async Delegates, CallBack and UI Thread

D

dm_dal

Gentlemen,
My question is simple. When my WindowsForm calls an Async Delegate which
has a registered CallBack, is the CallBack always executed on the UI Thread?
Or, do I need to test to see if it is?

In my application (MDI), I have a main form that launches another form.
When that child form loads it executes an Async Delegate who's target is a
method on a static class (Controller). The CallBack is registered on the
child form. In the callback, I check the IAsyncResult and if it was
successful, I want to trigger an event on the MDIParent to launch another
WindowsForm. Problem is, the second form is never launched. I can step
through the execution in the debugger, and can see the callback getting
executed, it runs to the event call and then everything stops. UI doesn't
freeze or anything like that, it just doesnt launch the second form. I have
noticed that sometime the second form does launch, but it appears as though
the thread it's on is blocked. It appears briefly, freezes, and then
disappears.

It definately appears as though the callback is executing on the worker
thread and that the events are being fired in that worker thread. That
would explain the blocking and possibly the reason for the form to close
(apparently after the thread is finished processing).

If it is on another thread, then would I use the ISynchronizeInvoke
interface to test whether the callback is on the UI thread? How would I
reference the form where the callback is registered?

David Young
 
S

Sijin Joseph

The callback is being executed on a thread from the ThreadPool, async
delegates and synchronous callbacks from that delegate will always use a
thread from the default threadpool. Launching a second form on the new
thread which does not have a message pump associated with it, is not a
good idea at all. So you need to figure out a way to launch the new form
from the orignal thread ( which has a message pump, created when you
make a call to Application.Run()).

http://msdn.microsoft.com/msdnmag/issues/04/01/NET/default.aspx

It might be possible to start a message pump for the second thread too
(by starting the second form using Application.Run()), sounds very flaky
though. Give it a shot if you can.

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph
 
D

dm_dal

I suspected as much, now on to my next question from the original post. How
do I go about making sure the launch of the new form is done on the UI
thread? Assume the following:

public class myForm : System.Windows.Forms.Form
{
private delegate bool myAsyncDelegate();
private System.Window.Forms.Button runButton;
private AppController controller = AppController.Instance; //singleton
class

public myForm()
{
}

private void openNewWindow()
{
form2 newForm = new form2();
newForm.MDIParent = this.MDIParent;
newForm.Show();
}
private void runButton_Click(object sender, System.EventArgs e)
{
myAsyncDelegate job = new
myAsyncDelegate(controller.ExecuteLongProcess);
job.BeginInvoke(new AsyncCallback(this.myAsyncCallback),null);
}

private void myAsyncCallback(IAsyncResult ar)
{
AsyncResult aResult = (AsyncResult)ar;
myAsyncDelegate del = (myAsyncDelegate)aResult.AsyncDelegate;
while(!ar.IsCompleted){Application.DoEvents();}
if(del.EndInvoke(ar))
{
// How do I code this line to ensure it's being executed on the
UI Thread?
this.openNewWindow();
}
}
}

How do I make sure the new window is launched on the UI thread?

I've seen examples of using the Invoke method, but none of the examples
support what I'm doing.

Would I use something like:
if(del.EndInvoke(ar))
{
if(this.InvokeRequired)
{
this.Invoke(this.openNewWindow);
}
else
{
this.openNewWindow();
}
}

David Young
 
D

dm_dal

Ok, after a little more research I found the solution. (Thanks for the link
Sijin!)

Using the same assumed class:
public class myForm : System.Windows.Forms.Form
{
private delegate bool myAsyncDelegate();

<added code>
private delegate void callbackDelegate();
private callbackDelegate openWindow;
private System.Window.Forms.Button runButton;
private AppController controller = AppController.Instance; //singleton
class

public myForm()
{

<added code>
openWindow = new callbackDelegate(openNewWindow);
}

private void openNewWindow()
{
form2 newForm = new form2();
newForm.MDIParent = this.MDIParent;
newForm.Show();
}
private void runButton_Click(object sender, System.EventArgs e)
{
myAsyncDelegate job = new
myAsyncDelegate(controller.ExecuteLongProcess);
job.BeginInvoke(new AsyncCallback(this.myAsyncCallback),null);
}

private void myAsyncCallback(IAsyncResult ar)
{
AsyncResult aResult = (AsyncResult)ar;
myAsyncDelegate del = (myAsyncDelegate)aResult.AsyncDelegate;
while(!ar.IsCompleted){Application.DoEvents();}
if(del.EndInvoke(ar))
{
// How do I code this line to ensure it's being executed on
the UI Thread?

<modified code>
//this.openNewWindow();
if(this.InvokeRequired)
{
this.Invoke(openWindow)
}
else
{
this.OpenNewWindow();
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top