ThreadStateException from background thread manipulating its control

Hi, I came to this exception: Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. and I don't know what to do with it.

My application creates some Panels with a lot of components at run time (according to the database entries). Each panel takes a second or two to load so I decied to use multithreading and choosed the ThreadPool.

Simply something like that:

(for each page in Form_Shown)
Thread.QueueUserWorkItem( <delegate to CreateFormPage> )
...
private Panel CreateFormPage(byte page)
{
Panel r = new Panel();
ComboBox cbx = new ComboBox(); // for example, in fact using reflection on control type stored in table
cbx.AutoCompleteMode = AutoCompleteMode.Suggest; // ThreadStateException
...
r.Controls.Add(cbx);
return r;
}

I know that I cannot modify the form from another thread than the GUI one, but I'm creating the controls on the separate thread and modifying them from the same thread (planning to add the final panel to the form in the GUI thread)... this is also illegal How should I do it then



Answer this question

ThreadStateException from background thread manipulating its control

  • Jcastro

    Does this mean I cannot prepare the controls on the background thread Does this mean I am not able to use multithreading at all

    Why is the exception never thrown during the control's creation


  • Ayo Soul

    Well I did a win32 stuff a long time ago and know that combobox styles are being set using messages and style values, but I thought it's handle to do that can be used without the form's handle.

    If not possible, well not possible. So, I would than ask: As far as knowing win32 stuff I absolutely don't know about Invoke/BeginInvoke - does this interrupt the main thread from doing the other GUI things (like repainting). If so, is there any way to 1] prepare the panels simultaneously or 2] run the Layout stuff on different thread (no control properties other than this 'bounds' stuff are being changed)

    Second solution, that cames to my mind... to override the WndProc and manually dispatch the messages I need to


  • RussellF

    You can use multithreading to do most of the work (for example, figuring out what type you need to create and using reflection to get the ConstructorInfo that you want to call), and then use Invoke to actually create the control. The exception is not thrown during the control's creation because technically nothing goes wrong there. The control is added to its parent successfully. But UI controls are not thread safe, and the UI thread might try to manipulate the control at any time, so any time you try to manipulate the control on another thread, you have the potential for a conflict.

  • Takrim Khan

    Because there are about 50 controls on the page, and by control I mean for example heading+control image+option buttons group+validaton image. These perform autosize, are wrappable and aligned like free flowlayout... like a web page :).

    Only part of the application deals with these pages. And even in this part, sooner than you realize and choose by which data you want to fill all these controls, they are already loaded.

    Ok the initial layout takes such long time, the resize is not so expensive, say second or two. (maybe there should be no difference, though)

    In fact, I have found that this operation takes so much time only on my development machine, I have tried it on another (much slower) and the complete startup with initial layouts is done in two seconds, which is acceptable.
    So the calculation itself is not as bad as it looks like, in fact I have optimized it as much as I could, using DrawString instead of Labels, DrawImage instead of picture boxes, setting positions manually instead of tons of TablePanels with Docks set to Fill, adding all pages to the parent and changing only the Visible property instead of clearing the control collection and adding the right one. I don't believe much can be done more.

    I am asking firstly because I was surprised I cannot modify the controls from the thread which (without problems) created them and because I would like to let the user work with the app while preparing some other parts - only by chance they are not dependent on the user's action in my example.


  • Frank Corrao

    Invoke sends a message to the message pump for the control on which you are calling invoke. That message is processed like any other windows message, in the order in which it was inserted into the message queue; its not so much that it "interrupts" the main UI thread, as it uses that thread to do its work. But yes, the UI thread would be prevented from doing other things (like repainting) until the invoked message was finished. Begin/EndInvoke do the exact same thing asynchronously, i.e. BeginInvoke returns immediately, without waiting for the message to finish processing.

    Overriding WndProc wont help you any, because WndProc only gets called from the UI therad anyway.

    Why can you not simply create your controls on the UI thread If you do it in the load event of the form, everything will happen before the form is actually displayed, so the user wont see the controls appearing or anything. If the wait is too long, use some kind of splash page or "Please wait"/"Initializing" dialog to indicate that significant preparation work is occurring.



  • Devidas Joshi

    How can your user continue to interact with your form if you are in the middle of performing layout changes If it is taking tens of seconds to recalculate the layout of your form on every size change, you have bigger issues that you need to deal with. Why is it taking so long to adjust the layout of your form

  • P-ter

    Ok, I thought about overriding the WndProc to achieve the behaviour of Invoke you described, so there is no point in it.

    I can create them on the GUI thread, but all this layout computations takes a time. We're talking about tens of seconds. The thing is, that user can work with other parts of the application while loading these pages.

    Every resize of the form starts the layouting again. I would like to do this in the background, rather than let the user wait some seconds on every page open. (Well at first I was creating and layouting only "on demand" but it was horrible to click a tree node and look some time to "frozen" window, so I moved the initial computations to the application startup).

    Thank you for your help.


  • andrew M

    Even though your control hasnt been added to a form yet, that doesnt mean that certain aspects of its creation havent already taken place. The whole point is that you dont know what might be required for your control to operate correctly; especially for things like comboboxes, which are wrappers around a low-level win32 implementation. The .NET framework is built on the assumption that all controls are created and manipulated on a single UI thread; if you dont follow that, you are likely to get unexplainable errors, even if you think that there is no reason why it shouldnt work. If you want to use the .NET framework, you have to follow its rules, and this is one of them (a big one actually).

  • Xavier Navarro

    Unfortunately, most of the work is Layouting, in front of which is the reflection creation zero-time operation. (In fact I am creating about 500 controls splitted into 13 pages/panels, at the moment)

    Adding the pages to the parent form is the last operation needed, with which I count to be held by the UI thread.

    There is no reason for UI thread to try to manipulate with my controls as it doesn't know about them, does it

    As long as the message pump is mentioned, I don't know about any message needed to be sent to my controls through the form - just because they aren't on the form!


  • Jendk

    Only the thread on which you called Application.Run is pumping the message loop, therefore it is the only thread on which it is legal to create and manipulate controls. Any other thread which needs to manipulate UI elements should use Begin/End/Invoke.

  • ThreadStateException from background thread manipulating its control