3

Я работаю с фоновым работником на C#. Вот это класс, а под ним, вы найдете instansiation его, и под там я буду определять мою проблему для вас:C# opennetCF background worker - e.result дает ObjectDisposedException

У меня есть класс Drawing:

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

} 

Instansiating объект этот класс:

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. 
    } 

} 

Вот моя проблема: В частном ничтожной bgWorker_RunWorkerCompleted (объект отправителя, RunWorkerCompletedEventArgs е)

Я не получаю 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"); 
     } 
    } 

ответ

0

Вы создаете интерфейс управления (панели) в другом потоке и возвращая панель контейнера обратно в основной поток. Элементы управления пользовательского интерфейса имеют сходство потоков. Когда фоновая работа завершается, поток, который он использует, возвращается в пул потоков, и во время этого процесса элементы управления пользовательского интерфейса, связанные с этим потоком, по-видимому, расположены. Когда позже вы попытаетесь использовать выделенный объект панели в обработчике событий RunWorkerCompleted в своем основном потоке, вы получите ObjectDisposedException.

Вам необходимо создать эти панели в основной теме, где находится ваш пользовательский интерфейс. Вы можете создать их в обработчике событий ProgressChanged, который запускается в основном потоке, или вы можете вызвать другой метод, который проверяет, InvokeRequired и если он это делает, а затем вызывает операцию в основном потоке, вызывая метод Invoke. Вы можете скрыть эти панели до тех пор, пока все они не будут созданы, а в обработчике событий RunWorkerCompleted вы можете их показать.

Предлагаю вам ознакомиться с нижеприведенным блогером.

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

+0

Я надеялся, чтобы не попасть в призыве, но похоже, что я должен сделать это таким образом .... – Ikky

1

Я не могу следовать код, «imagePanel», кажется, падает с неба, без какого-либо понятия, как он был создан. Однако то, что вы делаете, совершенно незаконно, Windows требует, чтобы родительский элемент управления (установленный вашим вызовом Controls.Add()) был окном, созданным в том же потоке, что и дочерний. .NET 2.0 обычно проверяет это и генерирует исключение IllegalOperationException, когда вы нарушаете это правило, трудно угадать, почему они оставят это из CF. Если они на самом деле это сделали.

ObjectDisposedException обычно встречается с BackgroundWorker при запуске события RunWorkerCompleted или ProgressChanged, и форма закрыта. Вы всегда должны быть уверены, что отмените BGW, прежде чем позволить форме исчезнуть. Это не имеет никакого значения здесь, вы должны полностью перепроектировать это в любом случае.

+0

Моя ошибка .... «imagePanel» должно быть «panelContainer» – Ikky

+0

я изучу вызывая это в любом случае сейчас ... просто я где-то читал, что использование фонового работника вызывало вас. Я использовал регулярную тему раньше, но друг меня сказал мне, что рабочий стол был настолько фантастическим, что я должен был его попробовать ... – Ikky

+0

Он перестает быть фантастическим, когда вы делаете много разговоров и фактически управляете большинством код в потоке пользовательского интерфейса. Затем вы просто замедляете свой код. Много. Спросите своего друга об этом. –