Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 保持窗体实例打开的任务?_C#_.net_Winforms_Asynchronous_Task Parallel Library - Fatal编程技术网

C# 保持窗体实例打开的任务?

C# 保持窗体实例打开的任务?,c#,.net,winforms,asynchronous,task-parallel-library,C#,.net,Winforms,Asynchronous,Task Parallel Library,我有一个Windows窗体,可以打开另一个窗体。在第二种形式中,它异步启动任务。如果用户启动任务,然后取消任务并快速关闭表单,则表单将被释放并设置为null。但是,当任务取消后返回时,我仍然会收到一个MessageBox。显示发生的情况 public class MyMainForm : Form { public void OpenChildForm() { MyChildForm form = new MyChildForm(); form.ShowDialog(

我有一个Windows窗体,可以打开另一个窗体。在第二种形式中,它异步启动任务。如果用户启动任务,然后取消任务并快速关闭表单,则表单将被释放并设置为null。但是,当任务取消后返回时,我仍然会收到一个MessageBox。显示发生的情况

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();
  }
}

这是有道理的。
任务
已停止异步执行,其执行生命周期与
表单
的生命周期无关。如果
表单
已被处理,您只需添加一个明确的检查,以确保不显示
消息框

if(result == Cancelled
            &&
   !(this.Disposing
           ||
    this.IsDisposed))
{
    MessageBox.Show("Cancelled");
}

表单的实例仍然存在,即使窗口可能不可见。要确保关闭表单后不显示
消息框
,请将事件添加到
OnClosing
,并将成员变量
m_formClosed
设置为
true
。仅当成员变量为
false
时显示消息

if (result == Cancelled && !m_formClosed)
    MessageBox.Show("Cancelled");
表单被释放并设置为null,但是当任务取消后返回时,我仍然会收到一个MessageBox。Show cover

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();
  }
}
将引用表单的变量设置为null,甚至对表单调用Dispose(),实际上并不会破坏表单。任务仍在执行,直到被取消(
CancellationTokenSource
被设计为用于取消的协作模型)

因此,您需要显式处理任务取消时发生的代码路径。这可能与检查您是否已被处置一样简单,即:

if (this.IsDisposed)
    return; // Just break out if we canceled and shut down

// Your other code....
if (result == Cancelled)
    MessageBox.Show("Cancelled");

尽管您调用了
Dispose()
并将引用设置为null,但GC可能尚未收集表单。这是正常的,因为GC是不确定的


由于
IDisposable
的实现方式,您可以检查表单上的
IsDisposed
IsDisposing
属性,查看
Dispose()
方法是否已被调用或正在运行。

另一件需要注意的事情:确保您没有调用
StartTask()
不止一次


如果是这样的话,您将得到多个异步任务,以及多个
CancellationTokenSource
实例(其中只有一个实例仍然由表单引用)。

但是为什么像UpdateLabel这样的东西不会掉下来呢,因为我本以为标签不存在,等等,这不应该是
&!(this.Disposing | | | this.IsDisposed)
?@ThorstenDittmar是的,忘了我的。更新示例。虽然我不明白为什么你说它没有被销毁,但我还是调用了dispose。我猜是因为GC还没有开始@Jon Dispose对内存(必然)或任何托管对象没有直接影响。它只不过是一种方法,(按照惯例)用于释放本机资源。它对CLR分配和管理的内存或对象没有任何影响。请参阅:诚然,所讨论的“资源”可能是内存,但也可能是其他任何东西(或什么都没有)。