Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Application.Run() on different threads

Please have a look at the following code:

var splashForm = new SplashForm();
m_Thread = new Thread( () => System.Windows.Forms.Application.Run( splashForm ) )
m_Thread.Start();

// Do some initialization
// ...

// the following method just invokes `Close()` on the right thread
splashForm.Shutdown();

// Loop until the thread is no longer alive
// ...

System.Windows.Forms.Application.Run( mainForm );

It looks as if all works fine: first I see the splashscreen, later the mainform gets started. But somehow I get strange errors, like: graphical elements (a endless ProgressBar) are not showing up correctly.
EDIT: I have two progressbars, one on the splashscreen, on on the mainform. They both show the same (wrong) behaviour in endlessmode: no progress, just the pure background./EDIT
In my opinion this is due to the call of Application.Run() on different threads. This errors can be eliminated by calling any function/property of the mainForm before starting the splashscreen - like, for instance

mainForm.Text = mainForm.Text;

Can anyone please confirm that this code can cause problems - or that it should behave alright and I have to look for the error somewhere else?
I already looked for splashscreen implementations and I know that it can be done differently. But I am interested in understanding this implementation and its possible problems. Thanks!

like image 853
tanascius Avatar asked Aug 03 '09 14:08

tanascius


4 Answers

The thread on which your SplashForm displays needs to have a Windows message pump in order to process messages that each window/control produces consumes. To do that you need to make the thread an STA thread. Try calling SetApartmentState before starting the thread

like image 133
Kevin Jones Avatar answered Nov 09 '22 04:11

Kevin Jones


I would create the form on the thread where the Application.Run() executes.

SplashForm splashForm = null;
m_Thread = new Thread(delegate { splashForm = new SplashForm(); System.Windows.Forms.Application.Run(splashForm); });
m_Thread.Start();

But what really needs to be done is access it via the InvokeRequired and BeginInvoke technique. Check here.

like image 23
Kenan E. K. Avatar answered Nov 09 '22 04:11

Kenan E. K.


OMG, I found the answer:
Application.EnableVisualStyles(); was called in the ctor if my mainForm (WHY?). It has to be called before any controls are created. Moving it to the static Main() did the trick. The visual styles are required for endless (ProgressBarStyle.Marquee) progressbars.
Now this splashscreen solution works as it should.

like image 2
tanascius Avatar answered Nov 09 '22 05:11

tanascius


There is nothing principally wrong with what you are doing. I found the approach interesting enough to whip up a demo, and it works fine. I can also say that kek444's answer isn't the problem. Creating the SplahForm on the main thread made no difference.

So I'm guessing it is in the way you control the Progressbar, or more generally how you communicate between the 2 threads.

like image 1
Henk Holterman Avatar answered Nov 09 '22 06:11

Henk Holterman