I recently added a login form to my application. This form shows prior to a splash screen that is shown while the main application form is loaded and various IO objects are instantiated.
Prior to the login form this is how my Program.cs would start the application
if (mutex.WaitOne(TimeSpan.Zero, true))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashScreen.ShowSplashScreen();
Application.Run(MainForm.Instance);
mutex.ReleaseMutex();
}
With the new login for the application is now started like so
if (mutex.WaitOne(TimeSpan.Zero, true))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
UserSessionSelection ussDialog = new UserSessionSelection();
if (ussDialog.ShowDialog() == DialogResult.OK)
{
SplashScreen.ShowSplashScreen();
Application.Run(MainForm.Instance);
}
mutex.ReleaseMutex();
}
Here is the SplashScreen
class
public partial class SplashScreen : Form
{
public static SplashScreen Instance { get { return lazyInstance.Value; } }
private static readonly Lazy<SplashScreen> lazyInstance =
new Lazy<SplashScreen>(() => new SplashScreen());
private SplashScreen()
{
InitializeComponent();
CenterToScreen();
TopMost = true;
}
static public void NewLoadingUpdate(String message, int percent)
{
NewUpdateDelegate nud = new NewUpdateDelegate(NewLoadingUpdateInternal);
SplashScreen.Instance.Invoke(nud, new object[] { message, percent });
}
static private void NewLoadingUpdateInternal(String message, int percent)
{
SplashScreen.Instance.lblLoadingText.Text = message;
SplashScreen.Instance.pgProgress.Value = percent;
}
private delegate void NewUpdateDelegate(String message, int percent);
private delegate void CloseDelegate();
static public void ShowSplashScreen()
{
Thread thread = new Thread(new ThreadStart(SplashScreen.ShowForm));
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
static private void ShowForm()
{
Application.Run(SplashScreen.Instance);
}
static public void CloseForm()
{
SplashScreen.Instance.Invoke(new CloseDelegate(SplashScreen.CloseFormInternal));
}
static private void CloseFormInternal()
{
SplashScreen.Instance.Close();
}
}
The error specifically happens with ShowForm
the specific text is
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.Windows.Forms.dll
Additional information: Cross-thread operation not valid: Control
'SplashScreen' accessed from a thread other than the thread it was created on.
The error only happens about 1/20 times when the application starts. I never encountered it prior to the login form.
Any ideas as to what causes this?
EDIT: For those late to the party, I think this SO question will help. Wait for a thread to actually start in c#