我有一个使用背景工作者的窗体。 backgroundworker实例化一个对象,然后在该对象中执行一个方法。我的问题是,当我使用backgroundworker.CancelAsync时,在远程对象上运行的方法不会停止。在下面的示例中,单击按钮取消后,dowork方法继续执行。仅供参考,dowork通过电子表格循环并根据电子表格中的行进行一些数据操作。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
myObject newObject = new myObject();
newObject.dowork();
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy) backgroundWorker1.CancelAsync();
}
思想?
由于
答案 0 :(得分:2)
在btnCancel_Click
中,您必须将取消请求传递给您的工作人员对象;否则,它将永远不会被通知。 BackgroundWorker.CancelAsync()
只是简单地设置BackgroundWorker.CancellationPending
属性,通知背景工作者的消费者(UI,而不是已执行的任务)您的任务已被取消,它不会做任何事情。
所以你需要的是:
MyObject 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 MyObject();
// 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 MyObject
{
// 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 && ...)
{
// ...
}
}
}