为什么我有时会遇到“无法访问处置对象”的异常?

问题描述:

我有这样的代码在我的背景DoWork事件:为什么我有时会遇到“无法访问处置对象”的异常?

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    BackgroundWorker worker = sender as BackgroundWorker; 
    while (true) 
    { 

     if ((worker.CancellationPending == true)) 
     { 
      e.Cancel = true; 
      break; 
     } 
     else 
     { 
      if (tempCpuValue >= (float?)nud1.Value || tempGpuValue >= (float?)nud1.Value) 
      { 
       soundPlay = true; 
       blinking_label(); 
       NudgeMe(); 
      } 
      else 
      { 
       soundPlay = false; 
       stop_alarm = true; 

      } 
      cpuView(); 
      gpuView(); 
     } 
    } 
} 

cpuView()方法我有这样的代码:

if (InvokeRequired) 
{ 
    this.Invoke(new Action(() => data = new List<string>())); 
    this.Invoke(new Action(() => data.Add("Gpu Temeprature --- " + sensor.Value.ToString()))); 
    this.Invoke(new Action(() => listBox1.DataSource = null)); 
    this.Invoke(new Action(() => listBox1.DataSource = data)); 
    this.Invoke(new Action(() => listBox1.Invalidate())); 
} 

异常/错误的这个时候上线:

this.Invoke(new Action(() => data = new List<string>())); 

这是我的Form1关闭事件:

private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
{ 
    if (MessageBox.Show("Are you Sure you want to Exit. Click Yes to Confirm and No to continue", "WinForm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     if (backgroundWorker1.WorkerSupportsCancellation == true) 
     { 
      backgroundWorker1.CancelAsync(); 
     } 
    } 
} 

一旦我退出我的应用程序,就会发生错误/异常,单击右上角的红色x并选择YES退出。

我该怎么办?

因此,这里的一部分问题是您没有充分利用BGW为您提供的功能。如果您从DoWork以内拨打Invoke,这意味着您没有真正使用BGW来完成它的工作。就你而言,你应该在BGW上打电话ReportProgress,然后有一个ProgressChanged事件处理程序,根据进度更新UI。您可以传入一个代表数据的参数来更新UI,因此您可以在DoWork内构建您的列表,并通过ReportProgress传递它,然后在ProgressChanged事件处理程序中设置DataSource

现在BGW负责在工人被取消后不报告进度。

+0

Servy感谢。如果你能告诉我一个如何去做的例子。非常感谢你。 – user2065612 2013-03-07 20:52:51

+0

@ user2065612我已经准确描述了您需要在分步说明中进行的操作。在Web上使用此行为以及后台工作人员的MSDN文档也有大量的详细示例。你不需要我给你完全完整的代码。你应该借此机会学习如何自己学习如何使用这个功能,因为如果你做了一些UI编程,你将需要做很多事情;你只需要能够自己做到这一点。 – Servy 2013-03-07 20:54:57

由于表单已关闭,其子控件和表单本身已处理。但是,WinForms继续在UI线程上处理未决的调用。这就是为什么它提出了“无法访问处置对象”。

Application.DoEvents()通常被描述为邪恶,但它的工作是在UI线程上处理所有挂起的消息。

在Close事件中完成后台线程是不够的。

这就是为什么我建议您在任何Dispose之前添加一个Application.DoEvents(),所以待处理的调用正在刷新,然后表单将优雅地关闭。

if (MessageBox.Show("Are you Sure you want to Exit. Click Yes to Confirm and No to continue", "WinForm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) 
{ 
    e.Cancel = true; 
} 
else 
{ 
    if (backgroundWorker1.WorkerSupportsCancellation == true) 
    { 
     backgroundWorker1.CancelAsync(); 
    } 

    Application.DoEvents(); 
} 

在Application.DoEvents的情况下()是用于你太哈克,可以通过使用封装InvokeRequired图案的扩展方法吞下的ObjectDisposedException:

public static void InvokeIfRequired(this Control control, Action action) 
{ 
    try 
    { 
     if (control.IsDisposed) 
      return; 

     if (control.InvokeRequired) 
      control.Invoke(action); 
     else 
      action(); 
    } 
    catch (ObjectDisposedException) 
    { 
     // There is nothing much we can do when an Invoke is pending on a disposed control 
     // the other exceptions will bubble up normally 
    } 
}