Make Thread-Safe Calls to Windows Forms Controls

  • Thread starter Thread starter Alexander Walker
  • Start date Start date
A

Alexander Walker

Hello

I want to get the value of a property of a control from a thread other than the
thread the control was created on, as far as I can see this is not the same as
invoking an operation on a control on a different thread I have used the
following code as per the guidance in the msdn documentation to invoke an
operation on a control from a thread other than which it was created

delegate void SetFormCursorCallback(Cursor cursor);

private void SetFormCursor(Cursor cursor)
{
if (this.InvokeRequired)
{
SetFormCursorCallback d = new
SetFormCursorCallback(SetFormCursor);
this.Invoke(d, new object[] { cursor });
}
else
{
this.Cursor = cursor;
}
}

What would I do if I wanted to access the Cursor property of the form and return
it to the caller on a different thread?

What techniques can I employ to do this?

Is there a way to make a synchronous call using a delegate that executes on a
different thread and then returns a value to the calling thread?

Thank you

Alex
 
Hi Alexander,

Thanks for your post.

Based on my understanding, you want to know how to get the cursor value
from another thread.

In .Net, Property is just a set/get methods accessor wrapper , so we should
also obey the .Net winform threading safe rule. So you should use the same
way as the code snippet you posted to get the Form cursor value.(Note: get
the Form cursor value means invoking the get_PropertyName() method Form
class )

I have writen a little sample to demonstrate this technology:

void GetCursorValue()
{
Cursor cs=this.Cursor;
MessageBox.Show(cs.ToString());
}

void ThreadProc()
{
if(this.InvokeRequired)
{
this.Invoke(new MethodInvoker(GetCursorValue), null);
}
else
{
MessageBox.Show("I am in UI thread, there is no need to do thread safe
operation!");
}
}
private void button1_Click(object sender, System.EventArgs e)
{
Thread t=new Thread(new ThreadStart(ThreadProc));
t.Start();
}

Hope this helps!

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Hi Jeffrey

I have been able to access the value of a controls property from another thread
in a thread safe manner by invoking a delegate that returns a value, The problem
that I now face is where I return a reference type such as a collection and I
try to loop through the collection from the thread other than that on which the
collection was created.

In my specific case I have a background worker that performs a lengthy operation
where it makes several calls to a webservice whilst accessing the selected items
collection of a list view, it needs to read selected items and then add new
items to the list view, I can add items to the list view in a thread safe manner
without any problems, but when I try to loop through the selected items
collection of the listview i get an exception telling me that it is not thread
safe, even though I obtained the reference in a threadsafe manner

heres the code

delegate ListView.SelectedListViewItemCollection
GetSelectedListViewItemsCallback();

private ListView.SelectedListViewItemCollection
GetSelectedListViewItems()
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
//
if (this.itemListView.InvokeRequired)
{
GetSelectedListViewItemsCallback d = new
GetSelectedListViewItemsCallback(GetSelectedListViewItems);
return this.Invoke(d) as
ListView.SelectedListViewItemCollection;
}
else
{
return itemListView.SelectedItems;
}

}

thanks

Alex
 
i think you can just access the property directly. as long as you
don't cause any changes to the UI which you are aware of already.
at least i have done this without any visible side-effects. i know you
can get away with bad multi-threading but you will sometimes see
strange things happening... this has never happened to me just by
reading a property of a control that was created on another thread.

tim
 
|i think you can just access the property directly. as long as you
| don't cause any changes to the UI which you are aware of already.
| at least i have done this without any visible side-effects. i know you
| can get away with bad multi-threading but you will sometimes see
| strange things happening... this has never happened to me just by
| reading a property of a control that was created on another thread.
|
| tim
|

This is true, but (unfortunately) in v2 of the framework, you will get an
'illigal cross-thread call' exception thrown on you in debug mode. That
means that all cross-thread accesses to UI elements are considered bad
practice.

Willy.
 
if we're talking .net 2.0, i would use the BackgroundWorker class and
pass in the cursor as the argument. if you are already using the
argument parameter, then send in an object array as the argument to the
RunWorkerAsync method, including the Cursor in the array. it is a
reference type so you should have a local/valid handle to it in the
worker thread.

hope this helps
tim
 
| if we're talking .net 2.0, i would use the BackgroundWorker class and
| pass in the cursor as the argument. if you are already using the
| argument parameter, then send in an object array as the argument to the
| RunWorkerAsync method, including the Cursor in the array. it is a
| reference type so you should have a local/valid handle to it in the
| worker thread.
|
| hope this helps
| tim
|

I think you misunderstood or maybe I wasn't clear enough. I'm just replying
to yours :
<
....this has never happened to me just by reading a property of a control
that was created on another thread.While it's perfectly valid to "read UI properties" in Windows, V2.0 of the
framework flags all UI accesses from non UI threads as illegal, which is not
true of course.

Willy.
 
Hi Alexander,

Thanks for your feedback.

Yes, I see your concern. This is because any manipulation to the UI thread
object from another thread needs to be marshalled with thread safe manner.
Regarding your scenario, we'd better place the loop through items code in a
method, then in the non-UI thread, we can use the Control.Invoke method to
invoke this method. Since the method code runs in the UI thread, no
marshaling is required in the method now.

Hope this helps

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Back
Top