c #opennetCF后台工作者 - e.result给出了ObjectDisposedException

时间:2010-03-27 13:42:51

标签: c# compact-framework backgroundworker opennetcf objectdisposedexception

我是C#的后台工作者。 这是一个类,在它下面,你会找到它的实例,在那里我将为你定义我的问题:

我有类绘图:

class Drawing
{
    BackgroundWorker bgWorker;
    ProgressBar progressBar;
    Panel panelHolder;

    public Drawing(ref ProgressBar pgbar, ref Panel panelBig)  // Progressbar and panelBig as reference
    {
        this.panelHolder = panelBig;
        this.progressBar = pgbar;
        bgWorker = new BackgroundWorker();
        bgWorker.WorkerReportsProgress = true;
        bgWorker.WorkerSupportsCancellation = true;

        bgWorker.DoWork += new OpenNETCF.ComponentModel.DoWorkEventHandler(this.bgWorker_DoWork);
        bgWorker.RunWorkerCompleted += new OpenNETCF.ComponentModel.RunWorkerCompletedEventHandler(this.bgWorker_RunWorkerCompleted);
        bgWorker.ProgressChanged += new OpenNETCF.ComponentModel.ProgressChangedEventHandler(this.bgWorker_ProgressChanged);
    }

    public void createDrawing()
    {
        bgWorker.RunWorkerAsync();
    }

    private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
    {
       Panel panelContainer = new Panel();

          // Adding panels to the panelContainer
          for(i=0; i<100; i++)
          {
            Panel panelSubpanel = new Panel();
            // Setting size, color, name etc....

             panelContainer.Controls.Add(panelSubpanel);  // Adding the subpanel to the panelContainer

             //Report the progress
             bgWorker.ReportProgress(0, i); // Reporting number of panels loaded
          }

          e.Result = panelContainer;   // Send the result(a panel with lots of subpanels) as an argument 
    }

    private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
          this.progressBar.Value = (int)e.UserState; 
          this.progressBar.Update();
    }

    private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            this.panelHolder          = (Panel)e.Result; 
        }
        else
        {
            MessageBox.Show("An error occured, please try again");
        }
    }

}

设置此类的对象:

public partial class Draw: Form
{
  public Draw()
  {


      ProgressBar progressBarLoading = new ProgressBar();
      // Set lots of properties on progressBarLoading 

      Panel panelBigPanelContainer = new Panel();          

      Drawing drawer = new Drawing(ref progressBarLoading, ref panelBigPanelContainer);

      drawer.createDrawing(); // this makes the object start a new thread, loading all the panels into a panel container, while also sending the progress to this progressbar.
  }

}

这是我的问题: 在private void bgWorker_RunWorkerCompleted(对象发送者,RunWorkerCompletedEventArgs e)

我没有得到应有的e.Result。 当我调试并查看e.Result时,面板的属性有以下异常消息:

'((System.Windows.Forms.Control)(e.Result)).ClientSize' threw an exception of type    'System.ObjectDisposedException'

所以对象被处理了,但“为什么”是我的问题,我该如何解决这个问题呢?

我希望有人能回答我,这让我发疯。 我有另一个问题:是否允许使用带有参数的“ref”?编程错了吗?

提前致谢。

我还写了下面我对以下背景工作者的理解:


我认为这是背景工作者的“规则”:

bgWorker.RunWorkerAsync();   => starts a new thread.
bgWorker_DoWork cannot reach the main thread without delegates

-

private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
       // The work happens here, this is a thread that is not reachable by 
          the main thread

       e.Result  => This is an argument which can be reached by
                    bgWorker_RunWorkerCompleted()


       bgWorker.ReportProgress(progressVar);  => Reports the progress to the
                                                 bgWorker_ProgressChanged()           

}

-

    private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
           // I get the progress here, and can do stuff to the main thread from here 
              (e.g update a control)

              this.ProgressBar.Value = e.ProgressPercentage;
     }

-

    private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // This is where the thread is completed.
        // Here i can get e.Result from the bgWorker thread
        // From here i can reach controls in my main thread, and use e.Result in my main thread


        if (e.Error == null)
        {
            this.panelTileHolder  = (Panel)e.Result;

        }
        else
        {
            MessageBox.Show("There was an error");
        }
    }

2 个答案:

答案 0 :(得分:1)

我不能按照你的代码,“imagePanel”似乎从天而降,没有任何想法它是如何创建的。但是,您所做的非常违法,Windows要求控件的父级(由您的Controls.Add()调用设置)是在与子级相同的线程中创建的窗口。 .NET 2.0通常会检查这一点,并在违反该规则时生成IllegalOperationException,很难猜出为什么他们会将其从CF中删除。如果他们确实这样做了。

ObjectDisposedException与BackgroundWorker的RunWorkerCompleted或ProgressChanged事件运行且窗体关闭时很常见。在允许表单消失之前,您必须确保取消BGW。这有点无关紧要,无论如何你必须完全重新设计。

答案 1 :(得分:0)

您正在另一个线程上创建UI控件(Panel)并将容器面板返回到主线程。 UI控件具有线程关联性。当后台工作者完成时,它使用的线程被释放回线程池,并且在该过程中,与该线程相关联的UI控件显然被丢弃。稍后您尝试在主线程中的RunWorkerCompleted事件处理程序中使用已处置的面板对象时,将获得ObjectDisposedException。

您需要在UI所在的主线程中创建这些面板。您可以在主线程中运行的ProgressChanged事件处理程序中创建它们,也可以调用另一个检查InvokeRequired的方法,如果是,则通过调用Invoke方法调用主线程上的操作。您可以隐藏这些面板,直到创建所有面板,并在RunWorkerCompleted事件处理程序中显示它们。

我建议你看看下面的博文。

WinForms UI Thread Invokes: An In-Depth Review of Invoke/BeginInvoke/InvokeRequred