My application's form is handling an event raised from a worker thread in
another object. In the event handler I want to call a sub procedure that
does a number of things and among those things is accessing controls on
the form. This sub procedure normally has been called from the Click
event procedure of a button on the form so there haven't been any issues
with accessing controls from outside the UI thread. Now I have to
consider this.

I could create delegates for all the procedures I need to Invoke on the
controls but I was hoping there was a simpler way. Is there any way to
force the UI thread to call a sub procedure without using Control.Invoke
()? For example:

Private myObj As MyObject

Private Sub MainForm_Load ...
...
AddHandler myObj.SomeEvent, AddressOf MyObject_SomeEvent
...
End Sub

Private Sub MyObject_SomeEvent(ByVal whatever As Integer)
' SomeEvent is raised by a worker thread in MyObject.
' How can I force the UI thread to call SomeProcedure
' from here so I don't have to litter the SomeProcedure
' Sub with If...Then...Else structures testing
' Control.InvokeRequired() and calling Control.Invoke()
' with various custom Delegates that I have to create?
End Sub

Private Sub SomeProcedure(ByVal whatever As Integer)
... Do Stuff
SomeTextBox.Text = "Gooney Goo Goo"
...
End Sub

Hopefully I'm making sense here. I may be a little confused and not
realize it yet.

Joel Moore

Re: Multithreaded WinForms question by Lee

Lee
Thu May 19 14:32:00 CDT 2005

Joel -

In my experience you are just going to have to bite the bullet on this.

What I try to do is organize my code by having anything that updates the
UI isolated to its own public method on the form. In these routines I
check to see if I am running on the UI thread, and if so I simply do the
UI update. If not I have the routine call itself with Form.Invoke. Then
I don't have to be so guarded about what thread I am working on, and it
makes it very simple adjust the way work is done amongst threads.

Wouldn't it be swell if the compiler could do this automatically for you
if it could possibly sense that UI updates are being performed within
the method body of a form routine? Or better yet if the UI calls that
need it were self marshalling?

Sometimes it is not completely clear to me when it is needed, and when
not. I think it should at least be a stock Framework documentation item
that says "Needs to be called in the UI thread", with a YES/NO on every
single routine in the windows forms library.

The reason this is an issue for me is that sometimes I forget to marshal
to the UI thread it works fine in testing, and then falls on its face
once deployed. It is always a hassle to find these after the fact.
Organizing my work with strict self-discipline as described above seems
to help me stay out of trouble.

- Lee

Joel Moore wrote:
> My application's form is handling an event raised from a worker thread in
> another object. In the event handler I want to call a sub procedure that
> does a number of things and among those things is accessing controls on
> the form. This sub procedure normally has been called from the Click
> event procedure of a button on the form so there haven't been any issues
> with accessing controls from outside the UI thread. Now I have to
> consider this.
>
> I could create delegates for all the procedures I need to Invoke on the
> controls but I was hoping there was a simpler way. Is there any way to
> force the UI thread to call a sub procedure without using Control.Invoke
> ()? For example:
>
> Private myObj As MyObject
>
> Private Sub MainForm_Load ...
> ...
> AddHandler myObj.SomeEvent, AddressOf MyObject_SomeEvent
> ...
> End Sub
>
> Private Sub MyObject_SomeEvent(ByVal whatever As Integer)
> ' SomeEvent is raised by a worker thread in MyObject.
> ' How can I force the UI thread to call SomeProcedure
> ' from here so I don't have to litter the SomeProcedure
> ' Sub with If...Then...Else structures testing
> ' Control.InvokeRequired() and calling Control.Invoke()
> ' with various custom Delegates that I have to create?
> End Sub
>
> Private Sub SomeProcedure(ByVal whatever As Integer)
> ... Do Stuff
> SomeTextBox.Text = "Gooney Goo Goo"
> ...
> End Sub
>
> Hopefully I'm making sense here. I may be a little confused and not
> realize it yet.
>
> Joel Moore

Re: Multithreaded WinForms question by Joel

Joel
Thu May 19 20:17:32 CDT 2005

Thanks. I've been bitten by this before and, yes, the bugs that arise
are often weird and unpredictable. I think it's happened to me enough
that now whenever I experience a strange and inexplicable error I
immediately go looking for this.

Anyway, I simply did the following:

--------------------------
Private Delegate SomeProcedureDelegate(ByVal whatever As Integer)
Private Sub SomeProcedure(ByVal whatever As Integer)
... Do Stuff
SomeTextBox.Text = "Gooney Goo Goo"
...
End Sub

Private Sub MyObject_SomeEvent(ByVal whatever As Integer)
Me.Invoke(New SomeProcedureDelegate(AddressOf SomeProcedure), _
New Object() {whatever})

End Sub
--------------------------

I guess my confusion stemmed from not realizing the Form object has an
Invoke method as well. I've been so used to calling Invoke on the
various controls that this never occured to me.

Joel Moore