I have a form which take a few seconds to load. So therefore, I want to show a little form with the text 'Loading, please wait'. When the form is finished loading, the loading form must be closed.
So, I made a simple class which Shows a loading form in a thread:
public class ShowLoadingForm
{
Thread _thread;
public void Show()
{
try
{
_thread = new Thread(new ThreadStart(ShowForm));
_thread.SetApartmentState(ApartmentState.STA);
_thread.IsBackground = true;
_thread.Start();
}
catch (Exception ex)
{
ErrorMessages.UnknownError(true, ex);
}
}
private void ShowForm()
{
LoadingForm f = new LoadingForm();
f.TopMost = true;
f.ShowInTaskbar = true;
f.SetText(" Loading... ");
f.Show();
}
public void Close()
{
_thread.Abort();
}
}
In the main form I have:
_loadingForm = new ShowLoadingForm();
_loadingForm.Show();
BUT. After this piece of code, I do something on the main form: this.Opacity = 0;. At this point, I can see in the debugger that the thread is stopped working and a ThreadStateException is thrown and the loading form is disappeared.
Why is this?
Your program bombs because you abort the thread but do not take care of the window. It is liable to try to run code because of a Windows notification, that will nosedive on ThreadStateException because the thread is aborted. You simply cannot end the thread by aborting it.
Here's a general class to solve this problem, it takes care of shutting down the waiting form and the thread cleanly.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
class Loader : IDisposable {
private AutoResetEvent initialized = new AutoResetEvent(false);
private Form loadForm;
private Rectangle ownerRect;
private bool closeOkay;
public Loader(Form owner, Form pleaseWait) {
if (pleaseWait.IsDisposed) throw new InvalidOperationException("Create a *new* form instance");
loadForm = pleaseWait;
loadForm.TopMost = true;
loadForm.ShowInTaskbar = false;
loadForm.StartPosition = FormStartPosition.Manual;
ownerRect = new Rectangle(owner.Location, owner.Size);
loadForm.Load += delegate {
loadForm.Location = new Point(
ownerRect.Left + (ownerRect.Width - loadForm.Width) / 2,
ownerRect.Top + (ownerRect.Height - loadForm.Height) / 2);
initialized.Set();
};
loadForm.FormClosing += new FormClosingEventHandler((s, ea) => {
ea.Cancel = !closeOkay;
});
var t = new Thread(() => {
Application.Run(loadForm);
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
initialized.WaitOne();
}
public void Dispose() {
if (loadForm == null) throw new InvalidOperationException();
loadForm.Invoke((MethodInvoker)delegate {
closeOkay = true;
loadForm.Close();
});
loadForm = null;
}
}
Sample usage:
private void button1_Click(object sender, EventArgs e) {
using (new Loader(this, new LoadingForm())) {
System.Threading.Thread.Sleep(3000);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With