Is it necessary to use Invoke for User Controls from a Worker Thread?

  • Thread starter Thread starter Charles Law
  • Start date Start date
C

Charles Law

I have a user control created on the main thread. Let's say, for arguments
sake, that it has a single property that maintains a private variable. If I
want to set that property from a worker thread, do I need to use
UserControl1.Invoke to set it, or can I just set it? After all, it is only
changing a private variable.

TIA

Charles
 
Hi, Charles

if variable is control - answer is you must use Invoke. If it is some object
non-related to UI, you can simply set it using lock statement. Lock -
because even if it is private variable if you have more than 1 thread you
might have synchronization problems.

You might want to check lock statement and volatile modifier in .Net
documentation to get more details.

HTH
Alex
 
----- Charles Law wrote: ----

After all, it is only changing a private variable

Famous last words
 
If you ignore thread-safety issues, the answer is no, you don't need to use
Invoke to update private fields from another thread. If you are actually
updating the screen, or perform an operation which directly or indirectly
calls an API that is thread sensitive, then you need to use Invoke.
 
Hi Alex

I'll come clean. I fibbed. I am updating a control, but I use Invoke for
that. What I actually have is a user control (UserControl1) that combines a
progress bar and a track bar. The track bar is used to set a value for the
progress bar, and when this happens the control raises an event to say that
it has happened.

This user control is placed on another user control (UserControl2), which
has a property 'Position'. This parent user control is then placed on a
form. The form also has a Position property.

The worker (background) thread can change the position as well, by

Form1.Position = 50

The form level Position property contains

UserControl2.Position = Value

The UserControl2 Position property contains

UserControl1.Position = Value

Finally, the UserControl1 Position property has

If ProgressBar1.InvokeRequired Then
' Use delegate and Invoke to set value
Else
' Set property directly
End If

As you will see, I have only used Invoke at the final stage, even though, if
I test UserControl2.InvokeRequired for example, at the higher level, I find
that it is True.

Does this mean that I should have, at the form level

If UserControl2.InvokeRequired Then
' Use delegate and Invoke to set value
Else
' Set property directly
UserControl1.Position = Value
End If

or am I ok with what I have?

Charles
 
Hi David

Thanks for the response. I have elaborated in my reply to Alex. Do you think
this changes anything? I don't want to ignore thread safety issues.

Charles
 
I didn't examine your code so I am not commenting on the specifics of what
you've done. The basic rule is actually quite simple: if setting a value
causes an operation to occur that is thread sensitive, then you must ensure
that you set the value while running on the correct thread. If all it is
doing is changing a simple field and there are no side effects, then it
should be safe to do so.

If the value you set is actually property setter, then you are doing more
then changing the value of a field, you are running code of unknown
complexity and which is potentially unbounded. Unless you are sure that the
code in the property setter will itself take care of threading issues, you
should do so before you call it. For example, if changing the property
causes events to get fired, then you could have a lot of problems if this
occurred on the wrong thread.
 
Hi David

Thanks for the rule. It has got me thinking.
For example, if changing the property
causes events to get fired, then you could have a lot of problems if this
occurred on the wrong thread.

You may have hit on something here. I'm away to check the code to see what
is actually happening.

Charles
 
The thread saftey issues of your private field aside, the only time you need
to use the Main Thread (UserControl1.Invoke) is for anything that will
update the UI. Its all about the painting. If 2 threads do something that
cause the form to repaint itself, it will take a big crap on you. If this
private member you are updating causes an event, the event is executed with
that thread. If that event changes a status bar on the form, then you gotta
move it over to the control's main thread.

I suggest in your private member, you use Invoke to fire the event from the
main thread.


--
Eric Marvets
Principal Consultant

the bang project

<shameless self promotion>

Email (e-mail address removed) for Information on Our Architecture and
Mentoring Services

</shameless self promotion>
 
Hi Eric

You mention the painting issue, and now you've got me thinking. I use Invoke
for controls, but I don't use it for 'painting' as such. I have code in the
OnPaint override, and I read that the graphics object passed in was thread
safe, so I use stuff like DrawRectangle without using Invoke. Are you saying
that I need to use Invoke even when using the graphics method to draw
things?

Charles
 
Yes. Thread saftey has a number of its own issues, but ignore those for
now.

Until Longhorn, WinForms is built on top of the Win32 API, and there all
messages sent to the Win32 API need to be done with the owner thread, or for
us the main thread in the application. It owns all the controls. In .NET
2.0, and exception is raised anytime this is not done. For now, I use the
rule of thumb, that if it does anything remotly graphical with the UI, I use
Invoke.

--
Eric Marvets
Principal Consultant

the bang project

<shameless self promotion>

Email (e-mail address removed) for Information on Our Architecture and
Mentoring Services

</shameless self promotion>
 
Back
Top