首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >BackgroundWorker取消

BackgroundWorker取消
EN

Stack Overflow用户
提问于 2014-11-24 04:40:30
回答 2查看 1.8K关注 0票数 2

我在我的winforms应用程序中使用一个BackgroundWorker来执行另一个类中发生的长时间运行的任务(执行数据库操作)。因为所有的工作都是在另一个类中完成的,所以取消就不那么简单了。当后台操作完成时,我使用另一个类中的一个事件(GenerateStats)来更新进度。我也想做一件类似的事情,取消手术。我不能只在cancellationPending函数中调用DoWork,因为方法在它完成之前永远不会看到它,这就违背了它的目的。我想要取消功能,而不需要将BackgroundWorker传递给generateForSubject()。这是否可以支持从generateForSubject()方法取消GenerateStats类。这是操作在其中执行的类的实例化:

代码语言:javascript
运行
复制
GenerateStats genStats = new GenerateStats();

这是我的DoWork函数,它在其他类中的事件被调用时调用ReportProgress方法。它还从执行操作的另一个类generateForSubject()调用方法。

代码语言:javascript
运行
复制
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;

    genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState);
    genStats.generateForSubject();
}

这是按钮单击事件处理程序,应该启动取消并运行CancelAsync()

代码语言:javascript
运行
复制
private void btnStop_Click(object sender, EventArgs e)
{
    if (backgroundWorker.IsBusy)
    {
        backgroundWorker.CancelAsync();
    }
}

这是执行操作的独立类,以及创建ProgressChanged事件处理程序,这样我的类就可以使用进度信息更新表单。如果取消可以执行类似的操作,那就太棒了。

代码语言:javascript
运行
复制
public event ProgressChangedEventHandler ProgressChanged;

protected virtual void OnProgressChanged(int progress, string message)
{
    if (ProgressChanged != null)
    {
        ProgressChanged(this, new ProgressChangedEventArgs(progress, message));
    }
}

public void generateForSubject()
{
    //Perform db operation not important, but it takes time

    OnProgressChanged(33, "Finished 1st set of stats");
    //I hope to check for cancellation here

    //Perform db operation not important, but it takes time

    OnProgressChanged(66, "Finished 2nd set of stats");
    //I hope to check for cancellation here        

    //Perform db operation not important, but it takes time

    OnProgressChanged(99, "Finished 3rd set of stats");
    //I hope to check for cancellation here
}

为了澄清我所要求的内容是否有任何不确定性,我是否有办法支持取消我在另一个类中的backgroundWorker,而不将backgroundWorker传递给该方法。如果没有绝对的办法,而且我必须这样做,那么我将通过backgroundWorker

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-24 05:25:58

如果您能够更具体地说明不愿意传递BackgroundWorker实例,这将是有帮助的。了解为什么这是一个设计要求,可以帮助您更好地回答您的问题。

也就是说,您可以应用与ProgressChanged事件相同的理念,也可以委托取消检查。例如:

代码语言:javascript
运行
复制
class GenerateStats
{
    public event EventHandler<CancelEventArgs> CheckCancel;

    private bool OnCheckCancel()
    {
        EventHandler<CancelEventArgs> handler = CheckCancel;

        if (handler != null)
        {
            CancelEventArgs e = new CancelEventArgs();

            handler(this, e);

            return e.Cancel;
        }

        return false;
    }

    public void generateForSubject()
    {
        //Perform db operation not important, but it takes time

        OnProgressChanged(33, "Finished 1st set of stats");
        if (OnCheckCancel())
        {
            // Or other cancellation logic here
            return;
        }

        //Perform db operation not important, but it takes time

        OnProgressChanged(66, "Finished 2nd set of stats");
        if (OnCheckCancel())
        {
            // Or other cancellation logic here
            return;
        }

        //Perform db operation not important, but it takes time

        OnProgressChanged(99, "Finished 3rd set of stats");
        if (OnCheckCancel())
        {
            // Or other cancellation logic here
            return;
        }
    }
}

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;

    genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState);
    genStats.CheckCancel += (sender1, e1) => e1.Cancel = worker.CancellationPending;
    genStats.generateForSubject();
}

这允许GenerateStats类在不直接访问BackgroundWorker实例的情况下检查挂起的取消,就像ProgressChanged事件允许它通过BackgroundWorker报告进度而不直接访问BackgroundWorker一样。

票数 4
EN

Stack Overflow用户

发布于 2014-11-24 04:58:22

您的方法应该定期检查CancellationPending属性,以确定是否提出了取消请求。然后决定取消手术。有关此问题,请参见MSDN链路

来自MSDN:

请注意,DoWork事件处理程序中的代码可能会在发出取消请求时完成其工作,并且轮询循环可能会错过将CancellationPending设置为true。在这种情况下,即使发出了取消请求,RunWorkerCompleted事件处理程序中的已取消标志也不会设置为true。这种情况称为争用条件,是多线程编程中常见的问题。有关多线程设计问题的详细信息,请参阅托管线程最佳实践。

编辑:

如果不希望将背景工作者传递给generateForSubject方法。当收到CancelAsync时,在类中设置一个属性。并在每次操作之前从generateForSubject方法中检查此属性的值。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27097968

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档