Windows Develop Bookmark and Share   
 index > Windows Forms General > cross Thread control accessbility
 

cross Thread control accessbility

I am having a serious problem with accessing controls in another thread. This is the runtime error message I get. I want to describe the setup in general terms without displaying the code since it is large and complicated and would need a lot of editing for clarity if I am to do it.

What I hope to get from this post is a general recommednation as to how such problems should be handled. It more information is desirable I will post the code.

I have a Form1 class. There is another class, BuildNewTabsPages, that generates new TabPages for my TabControlon demand. When a new TabPage is created all its subcontrols end up in a Thread in the ThreadPool, I suppose.

When the new TabPage is created by calling a function makeNewIntraDayPAGE with the return type TabPage located in classBuildNewTabsPages this function also creates a graphic (plot). So far so good. It works fine.

The new TabPage also has 4 TextBox controls and the plot object which is not a control has a DataSource property. Once in a while the DataTable that is used as DataSource for the plot gets a new row and I want to update the whole setup.

First I tried to do it from the main Form1 class. I was getting runtime errors that I violated cross Thread access. After that I created a delegate that was supposed to do it painlessly. The delegate declaration and the function (method: hello) it uses are now a part of BuildNewTabsPages class but this method hello is called from Form1 class.

I still get the same runtime error after overcoming considerable difficulties to make the delegate work, studying MethodInfo and Delegate classes and making CreateDelegate method work.

If my write-up makes sense I would appreciate any comment. If not, what additional information is desirable--I will supply it.

Thanks.

P.S. As of latea number my posts have been dumped down to otherforums like .NET Developement by the mediator. I understand the reason for itbut it diminishes the chance of getting a response by a factor of 5 at least. This forum is the best in terms of participants knowledge and ability to explain. I would appreciate it being left in here.

Many thanks again.

AlexBB - Vista Ult64 SqlSer64 WinSer64  Tuesday, December 26, 2006 5:37 PM

A couple of things:

one: you can't access control data from any thread other than the thread that created (instantiated) the control. If you want to create child controls of another control then you have to create then in the same thread as the parent. Usually this means all your UI control creation is done in the main thread. If you want to modify control data from a background thread you have to invoke the code on the GUI thread or you will get an exception in .NET 2.0. You can do this through the Form's InvokeRequired/BeginInvoke property/method--usually in a method on the form to keep it coupled to the form--by simply recursing when necessary:

public void SetControlText ( String text )

{

if (InvokeRequired)

{

this.BeginInvoke((MethodInvoker)delegate( )

{

SetControlText(text);

});

}

else

{

this.control.Text = text;

}

}

If you plan on having a background thread that provides data that needs to be displayed to the user, the best route is to use the BackgroundWorker class and either update the UI in the Progress events or in the RunWorkerCompleted event as they are guaranteed to be executed on the thread that created the BackgroundWorker object.

Two: if you ask a question on a topic that belongs in a specific forum (in this case a WinForms forum) it will be moved. Other people use these forums to find answers to questions that have already been asked. If the threads are no in the correct forum they will have a hard time finding their answer, or won't find it at all.

Peter Ritchie  Tuesday, December 26, 2006 6:13 PM

Do you mean the Control.Refresh method? If so, following your previous post:

public void RefreshControl (System.Windows.Forms.Control clr )
{
if ( clr.InvokeRequired )
{
clr.BeginInvoke ( ( MethodInvoker )delegate ( )
{
RefreshControl( clr );
} );
}
else
{
clr.Refresh();
}
}

Peter Ritchie  Tuesday, December 26, 2006 7:32 PM
How it works? I'm not sure what you mean (it's self-explanitory to me :-).

The InvokeRequired basically compares the current thread with the thread that created the control--resulting in true if they are different threads. The BeginInvoke puts an event on the end of the control thread'sevent queue to be processed when the control's thread has time.

The method pattern we used simply causes the method to recurse itself if running on a background thread, ensuring the real processing in the method is performed on the thread that created the control.

It's not something you'd see in MSDN because it's application-specific and it's not something that happens by default because of the overhead (applications would be too slow if they checked which thread was running whenever modifying control data...).
Peter Ritchie  Wednesday, December 27, 2006 7:03 PM

A couple of things:

one: you can't access control data from any thread other than the thread that created (instantiated) the control. If you want to create child controls of another control then you have to create then in the same thread as the parent. Usually this means all your UI control creation is done in the main thread. If you want to modify control data from a background thread you have to invoke the code on the GUI thread or you will get an exception in .NET 2.0. You can do this through the Form's InvokeRequired/BeginInvoke property/method--usually in a method on the form to keep it coupled to the form--by simply recursing when necessary:

public void SetControlText ( String text )

{

if (InvokeRequired)

{

this.BeginInvoke((MethodInvoker)delegate( )

{

SetControlText(text);

});

}

else

{

this.control.Text = text;

}

}

If you plan on having a background thread that provides data that needs to be displayed to the user, the best route is to use the BackgroundWorker class and either update the UI in the Progress events or in the RunWorkerCompleted event as they are guaranteed to be executed on the thread that created the BackgroundWorker object.

Two: if you ask a question on a topic that belongs in a specific forum (in this case a WinForms forum) it will be moved. Other people use these forums to find answers to questions that have already been asked. If the threads are no in the correct forum they will have a hard time finding their answer, or won't find it at all.

Peter Ritchie  Tuesday, December 26, 2006 6:13 PM

Thank you, Peter,

I will have to studyyour answercarefully. I have been under impression that my situation preserves the thread integrity while the controls are created and when they are accessed as well. Apparently this is not the case as the runtime shows and I want to understand why.

I create the TabPage and all subcontrols in one function called from the main Form1 class. I thought it would garantee them to be set in one thread. The delegate that uses a method to access the controls is also created by the same function at the time the page and all subcontrols are created. I thought that the delegate will be a part of the same thread as well.

I do use the BackgroundWorker for another process. It is sort of bulky. Can I just invoke my own thread via Thread tdr = new Thread () and deal with it via delegates, creating the TabPage, etc. I can then store the pointer to this thread in a global List and easily access it when necessary. Is it a good plan?

Thanks.

AlexBB - Vista Ult64 SqlSer64 WinSer64  Tuesday, December 26, 2006 6:40 PM

Well, Peter, I owe you for this one. It seems to be working. It seems to have solved 1/2 of my problem. I will explain now what the second half is. I had to edit your code a bit and now it looks like this:

public void SetControlText (System.Windows.Forms.Control clr, String text )
{
if ( clr.InvokeRequired )
{
clr.BeginInvoke ( ( MethodInvoker )delegate ( )
{
SetControlText ( clr, text );
} );
}
else
{
clr.Text = text;
}
} // SetControlText

So far so good. My texboxes are being updated. Many thanks.

The remaining problem: I have two other crazy controls on this page that need to respond to Refresh() command. It breaks the code down. Do you have a variant of this SetControlText command for Refresh command? That might be the complete end of my development for this project.

An amazing method, I'll tell you. Very helpful.

AlexBB - Vista Ult64 SqlSer64 WinSer64  Tuesday, December 26, 2006 7:03 PM

Do you mean the Control.Refresh method? If so, following your previous post:

public void RefreshControl (System.Windows.Forms.Control clr )
{
if ( clr.InvokeRequired )
{
clr.BeginInvoke ( ( MethodInvoker )delegate ( )
{
RefreshControl( clr );
} );
}
else
{
clr.Refresh();
}
}

Peter Ritchie  Tuesday, December 26, 2006 7:32 PM
Peter Ritchie wrote:

Do you mean the Control.Refresh method? If so, following your previous post:

public void RefreshControl (System.Windows.Forms.Control clr )
{
if ( clr.InvokeRequired )
{
clr.BeginInvoke ( ( MethodInvoker )delegate ( )
{
RefreshControl( clr );
} );
}
else
{
clr.Refresh();
}
}

Well, it MAY be working! At least I do not get any runtime troubles anymore. The picture is still not what I expected it to be since I updated (refreshed) this control before in a model situation definitely from a single thread and the action/result looked different. However this point is beyond the scope of this post. I think the issue is closed. Thank you very much indeed.

How come the RefreshControl and SetControlText methods are not found in MSDN help?

AlexBB - Vista Ult64 SqlSer64 WinSer64  Tuesday, December 26, 2006 8:26 PM

Well, Peter, you've opened up a new world for me, so to speak. I even ventured into creating my own methods like you've shown. Now I have SetControlBackColor, etc.

I wish youwould explain how this code works. That would be very helpful.

Thank you very much.

AlexBB - Vista Ult64 SqlSer64 WinSer64  Wednesday, December 27, 2006 6:46 PM
How it works? I'm not sure what you mean (it's self-explanitory to me :-).

The InvokeRequired basically compares the current thread with the thread that created the control--resulting in true if they are different threads. The BeginInvoke puts an event on the end of the control thread'sevent queue to be processed when the control's thread has time.

The method pattern we used simply causes the method to recurse itself if running on a background thread, ensuring the real processing in the method is performed on the thread that created the control.

It's not something you'd see in MSDN because it's application-specific and it's not something that happens by default because of the overhead (applications would be too slow if they checked which thread was running whenever modifying control data...).
Peter Ritchie  Wednesday, December 27, 2006 7:03 PM

Peter Ritchie wrote:
How it works? I'm not sure what you mean (it's self-explanitory to me :-).

The InvokeRequired basically compares the current thread with the thread that created the control--resulting in true if they are different threads. The BeginInvoke puts an event on the end of the control thread'sevent queue to be processed when the control's thread has time.

The method pattern we used simply causes the method to recurse itself if running on a background thread, ensuring the real processing in the method is performed on the thread that created the control.

It's not something you'd see in MSDN because it's application-specific and it's not something that happens by default because of the overhead (applications would be too slow if they checked which thread was running whenever modifying control data...).

Thank you. It provides about 85% of comprehension. The rest 15% is: How come I name a method essentially off of hat and it works. I created such methods: DisposeControl and it seems to work, also SetControlBackColor and this one definitely works. I wonder how the compiler understands such language which is not regimented and not declared somewhere?

AlexBB - Vista Ult64 SqlSer64 WinSer64  Wednesday, December 27, 2006 8:56 PM
OK, I completely understood how it works. No further explanations are necessary. It is rather simple. Thanks.
AlexBB - Vista Ult64 SqlSer64 WinSer64  Friday, December 29, 2006 2:10 PM

You can use google to search for other answers

Custom Search

More Threads

• crystal report
• {SOLVED} how to know if item is selected in ListView
• How To Get AssemblyName of the application
• Move a picturebox around with the mouse
• Third party button doesn't support the method "PerformClick()", how to invoke its event handler function?
• how to find the tan inverse in c#
• Problems creating XML and Schema from SQL
• Graphics Question
• TextBoxRenderer without XP theme.
• Tooltips stop working when you click on control; any workaround?