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();
эта строка является проблемой, каждый раз, когда вы нажимаете кнопку, вы создаете новый экземпляр фонового рабочего. Вы должны определить, если за пределами метода это должно быть хорошо