2015-08-25 5 views
0

У меня проблема с реализацией кода, который я получил от stackowerflow, о том, что он убил процесс backgroundworker.C# backgroundworker и partial class

Мой код выглядит следующим образом:

using System; 
using System.Collections.Generic; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.IO; 
using System.Threading; 
using System.Text.RegularExpressions; 
using System.Runtime.InteropServices; 
using GluthGUI.Classes.XMLprofile; 
using System.Xml.Linq; 
using System.ComponentModel; 


namespace Solution 
{ 
    partial class SolGUI : Form 
    { 

     private void startButton_Click(object sender, EventArgs e) 
     {    



backgroundWorker1 = new AbortableBackgroundWorker(); 

      if (startButton.Text == "Start") 
      { 

       XMLParsing(); 


       DisableTextFields(); 

       backgroundWorker1.RunWorkerAsync();  

       startButton.Text = "Stop"; 

      } 
      else if (startButton.Text == "Stop") 
      { 

       if (backgroundWorker1.IsBusy == true) 
       { 
        backgroundWorker1.Abort(); //error Abort() is not declared?!?! 
        backgroundWorker1.Dispose(); 
       } 

       startButton.Text = "Start"; 
       DisableTextFields(); 
      } 
     } 
    } 

Это частичный класс, который бы прекратить BackgroundWorker:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.ComponentModel; 
using System.Threading; 

namespace Solution 
{ 
    public class AbortableBackgroundWorker : BackgroundWorker 
    { 
     private Thread workerThread; 

     protected override void OnDoWork(DoWorkEventArgs e) 
     { 
      workerThread = Thread.CurrentThread; 
      try 
      { 
       base.OnDoWork(e); 
      } 
      catch (ThreadAbortException) 
      { 
       e.Cancel = true; //We must set Cancel property to true! 
       Thread.ResetAbort(); //Prevents ThreadAbortException propagation 
      } 
     } 


     public void Abort() 
     { 
      if (workerThread != null) 
      { 
       workerThread.Abort(); 
       workerThread = null; 
      } 
     } 
    } 
} 

Моя проблема заключается в том, что Abort() метод частичного класса не видно в других классы с одинаковым пространством имен.

+3

вам действительно нужно использовать Прервать ли? Это не рекомендуется в большинстве ситуаций. Вместо этого используйте переменную или CancellationToken. – Robert

+0

Работает ли он, если вы используете AbortableBackgroundWorker в не-частичном классе? – Hamed

+0

Где (и как) определяется 'backgroundWorker1'? Является ли тип «AbortableBackgroundWorker»? Также он никогда не будет занят, поскольку вы каждый раз создаете новый экземпляр, чтобы никогда не было ничего, чтобы прервать его. – musefan

ответ

3

Проблема в том, что вы определяете backgroundWorker1 с типом BackgroundWorker, так что у вас нет доступа к пользовательским методам, определенным в вашем классе AbortableBackgroundWorker.

Либо добавить AbortableBackgroundWorker прямо в конструкторе, или объявить AbortableBackgroundWorker вручную в вашей форме:

partial class SolGUI : Form 
{ 
    AbortableBackgroundWorker backgroundWorker1 = new AbortableBackgroundWorker(); 

Вы также должны убедиться, что вы удалите эту строку кода с вашего события нажатия кнопки:

backgroundWorker1 = new AbortableBackgroundWorker(); 

потому что это вызывает новый экземпляр, который будет установлен каждый раз, когда вы нажимаете, и вы никогда не получите доступ к исходному экземпляру, чтобы прервать его. Вам также не следует располагать объект в любой момент, как вы хотите использовать его, когда вы снова начать процесс, так что удалить:

backgroundWorker1.Dispose(); 

Вам также необходимо подключить любые события, которые вы используете, например, DoWork , Вы должны сделать это в формах конструктора, как так:

backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork); 

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

+0

ОК, которая решила проблему с Abort(). Теперь вы можете объяснить, что вы имели в виду под «hook DoWork». Потому что у меня проблемы с методом backgroundWorker1.RunWorkerAsync(); не бегать. – user3787774

+0

@ user3787774: См. Edit – musefan

+0

Благодарим вас за ввод – user3787774

1

Переменная backgroundWorker1 была определена как BackgroundWorker, в то время как она должна быть определена как AbortableBackgroundWorker в другой части вашего частичного класса.

Возможно, вы нашли это как SolGUI.Desinger.cs в решении explorer.

-1
backgroundWorker1 = new AbortableBackgroundWorker(); 

Эта проблема является проблемой, каждый раз, когда вы нажимаете кнопку, вы создаете новый экземпляр рабочего стола. вы должны определить, если за пределами метода это должно быть в порядке

+0

Это не решит проблему с компиляцией кода, тип должен быть изменен на 'AbortableBackgroundWorker' – musefan

2

Если абонированной метод DoWork событие не является плагином или третий код партии, которая не может поддерживать, это, как правило very bad idea, чтобы прервать поток непосредственно.

Когда вы нажимаете кнопку «Стоп», вы должны передать запрос об аннулировании вашему рабочему объекту; в противном случае он никогда не будет уведомлен.BackgroundWorker имеет метод CancelAsync, который ничего не делает, просто устанавливает свойство BackgroundWorker.CancellationPending, уведомляя потребителя BackgroundWorker (пользовательский интерфейс, а не выполненная задача), что ваша задача была отменена.

Так что вам нужно:

MyWorkerObject myObject; 

// This method is executed on the worker thread. Do not access your controls 
// in the main thread from here directly. 
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    myObject = new MyWorkerObject(); 

    // The following line is a blocking operation in this thread. 
    // The user acts in the UI thread, not here, so you cannot do here 
    // anything but wait. 
    myObject.DoWork(); 

    // Now DoWork is finished. Next line is needed only to notify 
    // the caller of the event whether a cancel has happened. 
    if (backgroundWorker1.CancellationPending) 
     e.Cancel = true; 

    myObject = null; 
} 

private void btnCancel_Click(object sender, EventArgs e) 
{ 
    if (backgroundWorker1.IsBusy) 
    { 
     backgroundWorker1.CancelAsync(); 

     // You must notify your worker object as well. 
     // Note: Now you access the worker object from the main thread! 
     // Note2: It would be possible to pass the worker to your object 
     //  and poll the backgroundWorker1.CancellationPending from there, 
     //  but that would be a nasty pattern. BL objects should not 
     //  aware of the UI components. 
     myObject.CancelWork(); 
    } 
} 

И как вы должны реализовать оповещение:

public class MyWorkerObject 
{ 
    // normally you should use locks to access fields from different threads 
    // but if you just set a bool from one thread and read it from another, 
    // then it is enough to use a volatile field. 
    private volatile bool isCancelRequested; 

    // this will be called from the main thread 
    public void CancelWork() 
    { 
     isCancelRequested = true; 
    } 

    // This method is called from the worker thread. 
    public void DoWork() 
    { 
     // Make sure you poll the isCancelRequested field often enough to 
     // react to the cancellation as soon as possible. 
     while (!isCancelRequested && ...) 
     { 
      // ... 
     } 
    } 
} 
+0

благодарим вас за очень хороший и хорошо прокомментированный ответ! – user3787774