C# backgroundworker и частичный класс

У меня есть проблема с реализацией кода, который я получил из stackowerflow, насчет убийства фонового рабочего процесса.

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

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

Это частичный класс, который завершает работу фонового работника:

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() из частичного класса не виден в других классах с тем же пространством имен.

4 ответа

Решение

Проблема в том, что вы определяете 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);

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

Если подписанный метод DoWork Событие - это плагин или сторонний код, который вы не можете поддерживать, обычно очень плохая идея - прервать поток напрямую.

Когда вы нажимаете кнопку "Стоп", вы должны передать запрос на отмену вашему рабочему объекту; в противном случае он никогда не будет уведомлен. 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 && ...)
        {
            // ...
        }
    }
}

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

Возможно, вы сможете найти его как SolGUI.Desinger.cs в обозревателе решений.

backgroundWorker1 = new AbortableBackgroundWorker();

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

Другие вопросы по тегам