I have a scenario. (Windows Forms, C#, .NET)
- There is a main form which hosts some user control.
- The user control does some heavy data operation, such that if I directly call the
UserControl_Load
method the UI become nonresponsive for the duration for load method execution. - To overcome this I load data on different thread (trying to change existing code as little as I can)
- I used a background worker thread which will be loading the data and when done will notify the application that it has done its work.
- Now came a real problem. All the UI (main form and its child usercontrols) was created on the primary main thread. In the LOAD method of the usercontrol I'm fetching data based on the values of some control (like textbox) on userControl.
The pseudocode would look like this:
CODE 1
UserContrl1_LoadDataMethod()
{
if (textbox1.text == "MyName") // This gives exception
{
//Load data corresponding to "MyName".
//Populate a globale variable List<string> which will be binded to grid at some later stage.
}
}
The Exception it gave was
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.
To know more about this I did some googling and a suggestion came up like using the following code
CODE 2
UserContrl1_LoadDataMethod()
{
if (InvokeRequired) // Line #1
{
this.Invoke(new MethodInvoker(UserContrl1_LoadDataMethod));
return;
}
if (textbox1.text == "MyName") // Now it wont give an exception
{
//Load data correspondin to "MyName"
//Populate a globale variable List<string> which will be binded to grid at some later stage
}
}
BUT BUT BUT... it seems I'm back to square one. The Application again become nonresponsive. It seems to be due to the execution of line #1 if condition. The loading task is again done by the parent thread and not the third that I spawned.
I don't know whether I perceived this right or wrong. I'm new to threading.
How do I resolve this and also what is the effect of execution of Line#1 if block?
The situation is this: I want to load data into a global variable based on the value of a control. I don't want to change the value of a control from the child thread. I'm not going to do it ever from a child thread.
So only accessing the value so that the corresponding data can be fetched from the database.
I have had this problem with the
FileSystemWatcher
and found that the following code solved the problem:fsw.SynchronizingObject = this
The control then uses the current form object to deal with the events, and will therefore be on the same thread.
Along the same lines as previous answers, but a very short addition that Allows to use all Control properties without having cross thread invokation exception.
Helper Method
Sample Usage
Action y; //declared inside class
label1.Invoke(y=()=>label1.Text="text");
I know its too late now. However even today if you are having trouble accessing cross thread controls? This is the shortest answer till date :P
This is how i access any form control from a thread.
I found a need for this while programming an iOS-Phone monotouch app controller in a visual studio winforms prototype project outside of xamarin stuidio. Preferring to program in VS over xamarin studio as much as possible, I wanted the controller to be completely decoupled from the phone framework. This way implementing this for other frameworks like Android and Windows Phone would be much easier for future uses.
I wanted a solution where the GUI could respond to events without the burden of dealing with the cross threading switching code behind every button click. Basically let the class controller handle that to keep the client code simple. You could possibly have many events on the GUI where as if you could handle it in one place in the class would be cleaner. I am not a multi theading expert, let me know if this is flawed.
The GUI form is unaware the controller is running asynchronous tasks.
I find the check-and-invoke code which needs to be littered within all methods related to forms to be way too verbose and unneeded. Here's a simple extension method which lets you do away with it completely:
And then you can simply do this:
No more messing around - simple.