【问题标题】:C# - How to work with background worker with custom code -Run,Pause,Stop?C# - 如何使用自定义代码与后台工作人员一起工作 - 运行、暂停、停止?
【发布时间】:2014-01-29 20:29:36
【问题描述】:

我正在使用 Background Worker,但我无法同步我的进度条,也无法停止或中止进程。

在我的工作函数中

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    if(bw.CancellationPending==true)
    {
        e.cancel=true;
        return;
    }
    else
    {
        e.Result = abc();
    }
}
int abc()
{
    //my work
    Count++;
    return count;
}

void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if(bw.CancellationPending==true)
    {
        button17.Visibility = Visibility.Visible;
        label1.Content = "Aborted";
    }
    button17.Visibility = Visibility.Visible;
    label1.Content = "Completed";
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
    if(bw.IsBusy)
    {
        bw.CancelAsync();
    }
}

现在我想知道如何同步进度条以及如何退出进程?

【问题讨论】:

    标签: c# backgroundworker


    【解决方案1】:

    您是否将实例上的BackgroundWorker.WorkerReportsProgress && BackgroundWorker.WorkerSupportsCancellation 属性设置为true

    例如

    var myBackgroundWorker = new BackgroundWorker();
    myBackgroundWorker.WorkerReportsProgress = true;
    myBackgroundWorker.WorkerSupportsCancellation = true;
    //the rest of the init
    

    如果您想报告进度,您需要从您的DoWork 内部调用BackgroundWorker.ReportProgress() 方法。

    【讨论】:

    • 我正在使用相同的属性,但仍然无法中止进程。对于BackgroundWorker.ReportProgress(),我需要传递哪些参数?
    • @neelb2 我已链接到该方法的 MSDN 页面,您可以访问智能感知。我想你可以弄清楚参数是什么。
    【解决方案2】:

    这是一个垃圾和微不足道的答案,但给 Task Parallel 库一个旋转。 http://msdn.microsoft.com/en-us/library/dd537608.aspx

    这个库将线程封装为离散的 Task 对象。它支持取消。

    请注意,在工作线程中,工作代码本身必须通过轮询暂停/取消标志和令牌来支持暂停和取消操作。仅使用线程无法安全地完成这些操作。

    这是一个更好的模式

    至于您的问题,需要 2 个标志来支持您的操作。您需要在工作代码期间定期检查它们。

    bool pause = false;
    bool cancel = false;
    void DoWork()
    {
        try
        {
            ...
            //periodically check the flags
            if(cancel) return;
            while(paused){}; //spin on pause
            ...
        }
        finally
        {
            //cleanup operation
        }
    }
    

    Alastair Pitts 的回答说明了后台工作人员如何支持这些功能。 MSDN 也是如此;)http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx

    【讨论】:

    • 我已经浏览了这个链接,它也没有以正确的方式帮助我。你有什么直截了当的解决方案吗?
    • 老实说,其他答案更好,但为了完整起见,我想向您提供有关任务模式的信息,因为它比后台工作人员实现的异步事件模式更灵活。我还想向您强调您应该采取的实际过程,以实现从后台工作人员中删除的取消和暂停 - 我在学习时发现事件焦点令人困惑。
    【解决方案3】:

    (您可能想查看 this 其他 SO 问题/答案,了解有关新 async 设施的详细信息!它极大地提高了开发此类运营的生活质量!)

    BackgroundWorker 是基于事件的,基本用法如下(链接提供了许多有用的附加细节):

    var worker = new BackgroundWorker();
    
    // The following two props must be true:
    // #1: The worker will be enabled to signal its progress
    worker.WorkerReportsProgress = true;
    // #2: The worker will accept cancellation
    worker.WorkerSupportsCancellation = true;
    
    // Now the events:
    
    worker.DoWork += (s,e) => 
    {         
        int i = 0; // This goes from 0 to 100
        // Do code, update 'i'
        worker.ReportProgress(i); 
    
        worker.CancelAsync();     //... to cancel the worker if needed
    
        // WARNING: This code *cannot* interact with the UI because
        // it's running in a different thread
    };
    
    worker.ProgressChanged += (s,e)=> 
    { 
    // This is executed when you call ReportProgress() from DoWork() handler
    // IMPORTANT: All UI interaction **must** happen here    
    
    // e.ProgressPercentage gives you the value of the parameter you passed to
    // ReportProgress() (this mechanism is a perfect fit for a progress bar!)
    };
    
    worker.RunWorkerCompleted+= (s,e) => 
    {
        // code here runs when DoWork() is done, is canceled or throws.
        // To check what happened, the link provides this sample code:
        if (e.Cancelled == true)
        {
            // Cancelled!
        }
        else if (e.Error != null)
        {
            // Exception !
        }
        else
        {
            // Work completed!
        }
    };
    
    worker.RunWorkerAsync();
    

    了解这一点很重要(摘自上面的链接):

    您必须小心不要在 DoWork 事件处理程序中操纵任何用户界面对象。相反,通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。

    UPDATE 此处的 Lambda 用于保持代码紧凑。您显然可以使用“普通”处理程序或任何其他将代码附加到您喜欢/想要/需要的事件的方法。

    【讨论】:

    • 使用 lambda 表达式作为事件处理程序是非常糟糕的做法 - 无法从调用列表中删除匿名委托。您能否更新您的答案以解释为什么在这种情况下可以?否则,答案很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多