Opened an instance of the assignment form?
I have a Windows form that opens another form. In its secondary form, it starts the task asynchronously. If the user starts the task and then cancels it and quickly closes the form, the form is Disposed and is null, but when the task returns due to cancellation, I still get a MessageBox.Show
public class MyMainForm : Form
{
public void OpenChildForm()
{
MyChildForm form = new MyChildForm();
form.ShowDialog();
form.Dispose();
form = null;
}
}
public class MyChildForm : Form
{
private CancellationTokenSource MyTokensource;
private Task task;
public void StartTask()
{
MyTokensource = new CancellationTokenSource();
task = Task.Factory.StartNew(() => MyMethod(MyTokensource.Token), MyTokensource.Token);
}
public void MyMethod(CancellationToken token)
{
var result = StaticClass.DoSomethingLengthy(token); //The cancel make take a couple of seconds to return here
if (result == Cancelled)
{
MessageBox.Show("Cancelled");
UpdateLabel("Cancelled")
}
}
public void ButtonClose_Click()
{
if (task != null && !task.IsCompleted)
{
MyTokensource.Cancel();
}
this.Close();
}
}
source to share
the form is Disposed and is null, but when the task returns after being canceled, I still get the MessageBox.Show message
Setting a variable that is a reference to a form to null, and even calling Dispose () on a form, does not actually destroy the form. The task is still running until canceled ( CancellationTokenSource
designed as a collaborative model for cancellation).
Thus, you need to explicitly handle the code path that occurs when the task is canceled. It can be as simple as checking if you have deleted yourself i.e.
if (this.IsDisposed)
return; // Just break out if we canceled and shut down
// Your other code....
if (result == Cancelled)
MessageBox.Show("Cancelled");
source to share
It makes sense. Task
turns off when executed asynchronously, its execution time is not tied to lifetime Form
. You just need to add an explicit check to make sure you don't show MessageBox
if Form
has already been / has been removed:
if(result == Cancelled
&&
!(this.Disposing
||
this.IsDisposed))
{
MessageBox.Show("Cancelled");
}
source to share
The form instance still exists, although the window may not be displayed. To make sure it MessageBox
doesn't show up after the form is closed, add an event to OnClosing
and set a member variablem_formClosed
to true
. Show message only when member variable false
.
if (result == Cancelled && !m_formClosed)
MessageBox.Show("Cancelled");
source to share
The GC may not have collected the form even though you are calling Dispose()
and setting the reference to null. This is fine as GC is not deterministic.
Because of the way the implementation IDisposable
, you can check the properties IsDisposed
and IsDisposing
in the form to find out whether the method Dispose()
has already been called or is in progress.
source to share