Reputation: 15039
I have the following WaitScreen class that shows a "please wait..." message when doing a background process:
public class WaitScreen
{
// Fields
private object lockObject = new object();
private string message = "Please Wait...";
private Form waitScreen;
// Methods
public void Close()
{
lock (this.lockObject)
{
if (this.IsShowing)
{
try
{
this.waitScreen.Invoke(new MethodInvoker(this.CloseWindow));
}
catch (NullReferenceException)
{
}
this.waitScreen = null;
}
}
}
private void CloseWindow()
{
this.waitScreen.Dispose();
}
public void Show(string message)
{
if (this.IsShowing)
{
this.Close();
}
if (!string.IsNullOrEmpty(message))
{
this.message = message;
}
using (ManualResetEvent event2 = new ManualResetEvent(false))
{
Thread thread = new Thread(new ParameterizedThreadStart(this.ThreadStart));
thread.SetApartmentState(ApartmentState.STA);
thread.Start(event2);
event2.WaitOne();
}
}
private void ThreadStart(object parameter)
{
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
ManualResetEvent event2 = (ManualResetEvent)parameter;
Application.EnableVisualStyles();
this.waitScreen = new Form();
this.waitScreen.Tag = event2;
this.waitScreen.ShowIcon = false;
this.waitScreen.ShowInTaskbar = false;
this.waitScreen.AutoSize = true;
this.waitScreen.AutoSizeMode = AutoSizeMode.GrowAndShrink;
this.waitScreen.BackColor = SystemColors.Window;
this.waitScreen.ControlBox = false;
this.waitScreen.FormBorderStyle = FormBorderStyle.FixedToolWindow;
this.waitScreen.StartPosition = FormStartPosition.CenterScreen;
this.waitScreen.Cursor = Cursors.WaitCursor;
this.waitScreen.Text = "";
this.waitScreen.FormClosing += new FormClosingEventHandler(this.WaitScreenClosing);
this.waitScreen.Shown += new EventHandler(this.WaitScreenShown);
Label label = new Label();
label.Text = this.message;
label.AutoSize = true;
label.Padding = new Padding(20, 40, 20, 30);
this.waitScreen.Controls.Add(label);
Application.Run(this.waitScreen);
Application.ExitThread();
}
private void WaitScreenClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
}
}
private void WaitScreenShown(object sender, EventArgs e)
{
Form form = (Form)sender;
form.Shown -= new EventHandler(this.WaitScreenShown);
ManualResetEvent tag = (ManualResetEvent)form.Tag;
form.Tag = null;
tag.Set();
}
// Properties
public bool IsShowing
{
get
{
return (this.waitScreen != null);
}
}
}
The way I use it is:
waitScreen = new WaitScreen();
waitScreen.Show("Please wait...");
I have a MainForm, inside a mainform I have a button, when clicked I show a Dialog that on load will get some data from database in a Backgroundworker. Before running the backgroundworker I show my WaitScreen.
Its working great but when the WaitScreen is displayed and If I click on the back Dialog then the WaitScreen is gone. So I want to block so I can't click on the back Dialog until the worker has finish and then I close my WaitScreen.
Any clue on how to do that?
Thanks a lot.
Upvotes: 0
Views: 1123
Reputation: 11252
I think you are overcomplicating this. What you want is a modal dialog window which the user can't close which will close when a given task is finished.
You can make a standard class which derives from Form
and implements a constructor or a property which you can pass a Task or a callback.
Here's what the code could look like in your WaitScreen
form:
public partial class WaitScreen : Form
{
public Action Worker { get; set; }
public WaitScreen(Action worker)
{
InitializeComponent();
if (worker == null)
throw new ArgumentNullException();
Worker = worker;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Task.Factory.StartNew(Worker).ContinueWith(t => { this.Close(); }, TaskScheduler.FromCurrentSynchronizationContext());
}
}
Here's what your code would look like in the consumer of this WaitScreen
form:
private void someButton_Click(object sender, EventArgs e)
{
using (var waitScreen = new WaitScreen(SomeWorker))
waitScreen.ShowDialog(this);
}
private void SomeWorker()
{
// Load stuff from the database and store it in local variables.
// Remember, this is running on a background thread and not the UI thread, don't touch controls.
}
You probably want to use FormBorderStyle.None in the WaitScreen so that the user can't close it. Then the task is complete the WaitScreen will close itself and the caller will continue execution of code after the ShowDialog()
call. ShowDialog()
blocks the calling thread.
Upvotes: 1