This is as compact as I could get it:
var waitingForm = new WaitingForm();
(new Thread (() => Application.Run(waitingForm))).Start();
HeavyWork();
waitingForm.BeginInvoke(new Action(() => waitingForm.Close()));
waitingForm
will be fully responsive, operating on the anonymous thread with its own message loop. However, since it is running on another thread, we need BeginInvoke
to close it.
We can swap this fire and forget thread with a Task
:
var waitingForm = new WaitingForm();
Task.Run(() => Application.Run(waitingForm));
HeavyWork();
waitingForm.BeginInvoke((Action)(() => waitingForm.Close()));
For an alternative that uses async, consinder the following:
var source = new TaskCompletionSource<int>();
Enabled = false;
ShowWaitForm();
await HeavyWorkAsync();
Enabled = true;
source.SetResult(0);
async void ShowWaitForm()
{
var waitingForm = new WaitingForm();
waitingForm.Show(this);
await source.Task;
waitingForm.Close();
}
This time we are using TaskCompletionSource
to notify that the work is finished and the WaitingForm
can be closed, in such way that we can await it.
There is a difference that the user will percieve: The MainForm
will be visible, and could even be responsive... we solve this by disabling it and making the WaitingForm
a child form.
Another difference is that in this case the WaitingForm
does not have its own message loop. However, it would still be responsive as long as you are using an async method to do your work.
Remember, it is a single thread handling both forms. This might or might not be convenient.
You can always fall back to use Task.Run
:
var source = new TaskCompletionSource<int>();
Enabled = false;
ShowWaitForm();
await Task.Run(() => HeavyWork());
Enabled = true;
source.SetResult(0);
async void ShowWaitForm()
{
var waitingForm = new WaitingForm();
waitingForm.Show(this);
await source.Task;
waitingForm.Close();
}
Note that when using Task.Run
on HeavyWork
, HeavyWork
is the part running in another thread. Now, it would need BeginInvoke
to interact with the MainForm
.
From there we can easily go to BackgroundWorker
:
var source = new TaskCompletionSource<int>();
Enabled = false;
ShowWaitForm();
var bg = new BackgroundWorker();
bg.DoWork += (_, __) => HeavyWork();
bg.RunWorkerCompleted += (_, __) =>
{
Enabled = true;
source.SetResult(0);
};
bg.RunWorkerAsync();
async void ShowWaitForm()
{
var waitingForm = new WaitingForm();
waitingForm.Show(this);
await source.Task;
waitingForm.Close();
}