Fire event in the same thread as the UI like BackgroundWorker

S

Sin Jeong-hun

This is what I've always been wondered.
Suppose I've created a class named Agent, and the Agent does some
lengthy job. Of course I don't want to block the main window, so the
Agent does the job in a separate thread. If the job is progressed it
fires an event, and the main window handled the event by changing the
value of a progress bar. The problem is that this event is fired in
another thread so when the handler in the main window tries to access
the progress bar, an exception occurs. Until now, I've been solving
this problem by checking InvokeRequired and creating a delegate.

But the .NET 2.0's built-in BackgroundWorker seems to have solved this
with a very elegant way. When a BackgroundWorker fires the progress
event, it looks like the event is fired in the same thread as the main
window, because the InvalidOperationException does not occur when I
try to access UI controls in the handler. How could this be possible?
I want my Agent class to be able to the same thing. Making a lot of
delegations in the main window code makes the code dirty.

Please give me an idea. Thank you.
 
P

Peter Duniho

Sin said:
[...]
But the .NET 2.0's built-in BackgroundWorker seems to have solved this
with a very elegant way. When a BackgroundWorker fires the progress
event, it looks like the event is fired in the same thread as the main
window, because the InvalidOperationException does not occur when I
try to access UI controls in the handler. How could this be possible?
I want my Agent class to be able to the same thing. Making a lot of
delegations in the main window code makes the code dirty.

Please give me an idea. Thank you.

I don't know the specifics of how BackgroundWorker does it. Since it
doesn't require a specific Control instance given to it, I suspect it's
using AsyncOperation or something similar.

I'm pretty sure it raises events on the same thread that created the
BackgroundWorker when possible (though, if I recall correctly that's not
actually what it does in a console application...it does depend on
having a message pump), not specifically the main UI thread.

You could either use AsyncOperation yourself (you'd initialize it when
your object is created, and then use it to raise events on the same
thread used to create the object). Alternatively, if your object
depends on a specific Control instance, you may find it easier to just
use the Control instance to invoke a method to raise the event.

Pete
 
G

Guest

Yes, BackgroundWorker uses AsyncOperation to marshal the call back to the
correct thread. It doesn't use a particular control thread, it simply uses
the thread that was used to create the BackgroundWorker object.

--
Browse http://connect.microsoft.com/VisualStudio/feedback/ and vote.
http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#


Peter Duniho said:
Sin said:
[...]
But the .NET 2.0's built-in BackgroundWorker seems to have solved this
with a very elegant way. When a BackgroundWorker fires the progress
event, it looks like the event is fired in the same thread as the main
window, because the InvalidOperationException does not occur when I
try to access UI controls in the handler. How could this be possible?
I want my Agent class to be able to the same thing. Making a lot of
delegations in the main window code makes the code dirty.

Please give me an idea. Thank you.

I don't know the specifics of how BackgroundWorker does it. Since it
doesn't require a specific Control instance given to it, I suspect it's
using AsyncOperation or something similar.

I'm pretty sure it raises events on the same thread that created the
BackgroundWorker when possible (though, if I recall correctly that's not
actually what it does in a console application...it does depend on
having a message pump), not specifically the main UI thread.

You could either use AsyncOperation yourself (you'd initialize it when
your object is created, and then use it to raise events on the same
thread used to create the object). Alternatively, if your object
depends on a specific Control instance, you may find it easier to just
use the Control instance to invoke a method to raise the event.

Pete
 
K

kentcb

Interesting. I hadn't seen the AsyncOperation class before. It's worth
noting that it is just a wrapper for the SynchronizationContext class
though. It is the particular current SynchronizationContext (available
via SynchronizationContext.Current) that does the actual work of
marshalling to the correct thread. If you're running Winforms, it'll
be a WindowsFormsSynchronizationContext. For WPF, it'll be a
DispatcherSynchronizationContext.

So AsyncOperation makes it easier to post progress and completion of
an operation to the UI (or "contextual") thread. Cool stuff.

Kent
 
S

Sin Jeong-hun

Interesting. I hadn't seen the AsyncOperation class before. It's worth
noting that it is just a wrapper for the SynchronizationContext class
though. It is the particular current SynchronizationContext (available
via SynchronizationContext.Current) that does the actual work of
marshalling to the correct thread. If you're running Winforms, it'll
be a WindowsFormsSynchronizationContext. For WPF, it'll be a
DispatcherSynchronizationContext.

So AsyncOperation makes it easier to post progress and completion of
an operation to the UI (or "contextual") thread. Cool stuff.

Kent

Right after I posted the original post, I thought maybe disassembling
the BackgroundWorker
would give me a hint. So I did it. It used several classes I'd never
seen before, and the logic
was quite unfamilar to me. But after all, I modified my class
according to the way BackgroundWoker
works, and now it works just like the BackgroundWorker. I don't need
to use InvokeRequired every time.
I think it would be worth for other people to try this.
Thank you for your replies, all.
 

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