c# backgroundworker 和部分 class

c# backgroundworker and partial class

我在执行从 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();
            }
        }
    }

这是一个部分 class,它将终止 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;
            }
        }
    }
}

我的问题是来自部分 class 的 Abort() 方法在具有相同命名空间的其他 class 中不可见。

问题是您正在定义类型为 BackgroundWorkerbackgroundWorker1,因此您无权访问 AbortableBackgroundWorker [=33= 中定义的自定义方法].

直接向您的设计器添加 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);

我不打算详细说明您是否应该中止线程,其他人已经评论过,如果您想听从他们的建议并进行一些研究,那是您的选择。我只是简单地回答了手头的问题。不过就个人而言,我会使用内置的取消方法。

变量 backgroundWorker1 已被定义为 BackgroundWorker 而它应该在您的部分 class.[=13= 的另一部分被定义为 AbortableBackgroundWorker ]

也许您可以在解决方案资源管理器中以 SolGUI.Desinger.cs 的形式找到它。

backgroundWorker1 = new AbortableBackgroundWorker();

这一行就是问题所在,每次单击按钮都会创建一个新的后台工作者实例。 你应该定义是否在方法之外 应该没问题

除非DoWork事件的订阅方法是一个插件或者你无法维护的第三方代码,否则通常是very bad idea直接中止一个线程。

当您单击“停止”按钮时,您必须将取消请求传递给您的工作对象;否则,它永远不会被通知。 BackgroundWorker 有一个 CancelAsync 方法,它不执行任何操作,只是简单地设置 BackgroundWorker.CancellationPending 属性,通知 BackgroundWorker 的消费者(UI,不是执行的任务)你的任务已经被取消了。

所以你需要什么:

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 && ...)
        {
            // ...
        }
    }
}