AutoResetEvent阻止BackgroundWorker进度报告

时间:2014-07-18 21:25:57

标签: c# wpf progress-bar backgroundworker autoresetevent

我在我的应用程序中使用BackgroundWorker。我可以在Backgroundworker仍然忙碌时显示进度条更改。但是当我使用AutoResetEvent等到Backgroundworker完成时,我没有看到进度条发生变化。有没有其他方法,我可以等待BackgroundWorker完成并取消进度条的更改?我是C#框架和编程的新手。

private AutoResetEvent _resetEvent = new AutoResetEvent(false);

private void InitializeBackgroundWorker()
        {
            parserBackgroundWorker.DoWork +=
                new DoWorkEventHandler(parserBackgroundWorker_DoWork);
            parserBackgroundWorker.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(
            parserBackgroundWorker_RunWorkerCompleted);
            parserBackgroundWorker.ProgressChanged +=
                new ProgressChangedEventHandler(
            parserBackgroundWorker_ProgressChanged);
            parserBackgroundWorker.WorkerReportsProgress = true;
            parserBackgroundWorker.WorkerSupportsCancellation = true;
        }

 private void parserBackgroundWorker_DoWork(object sender,
            DoWorkEventArgs e)
        {
            // Get the BackgroundWorker that raised this event.
            BackgroundWorker worker = sender as BackgroundWorker;

            parser.Parse((SegmentFile)e.Argument);
            _resetEvent.Set();
        }

        // This event handler deals with the results of the 
        // background operation. 
        private void parserBackgroundWorker_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs e)
        {
            // First, handle the case where an exception was thrown. 
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                // Next, handle the case where the user canceled  
                // the operation. 
                // Note that due to a race condition in  
                // the DoWork event handler, the Cancelled 
                // flag may not have been set, even though 
                // CancelAsync was called.
                //resultLabel.Text = "Canceled";
            }
            else
            {
                // Finally, handle the case where the operation  
                // succeeded.
                //resultLabel.Text = e.Result.ToString();
            }           
        }

        // This event handler updates the progress bar. 
        private void parserBackgroundWorker_ProgressChanged(object sender,
            ProgressChangedEventArgs e)
        {
            ProgressBar1.Value = e.ProgressPercentage;
        }

parserBackgroundWorker.RunWorkerAsync(selectedSegFile);
// when I comment this code I do see the progress bar change as the thread is doing the work.
_resetEvent.WaitOne();

2 个答案:

答案 0 :(得分:1)

假设你有这段代码:

parserBackgroundWorker.RunWorkerAsync(selectedSegFile);
_resetEvent.WaitOne();
MessageBox.Show("Work Done");

然后您可以在_resetEvent.WaitOne();方法中放置代码并将此方法附加到RunWorkerCompleted事件并删除_resetEvent.WaitOne();

private void MyRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    MessageBox.Show("Work Done");
}

private void InitializeBackgroundWorker()
{
    //old init code
    // you can attach as many methods to RunWorkerCompleted as you want
    parserBackgroundWorker.RunWorkerCompleted += parserBackgroundWorker_RunWorkerCompleted;
    parserBackgroundWorker.RunWorkerCompleted += myRunWorkerCompleted;
}

另外,您可以delegate作为BackgroundWorker的参数,并在parserBackgroundWorker_RunWorkerCompleted

中调用它
class ParserWorkerParameters
{
    public String SegFile { get; set; }
    public Action CallBack { get; set; }

    public ParserWorkerParameters(string segFile, Action callBack)
    {
       SegFile = segFile;
       CallBack = callBack;
    }
}

parserBackgroundWorker.RunWorkerAsync(new ParserWorkerParameters("someString", () =>  MessageBox.Show("worker complete")));

private void parserBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    ParserWorkerParameters param = e.Argument as ParserWorkerParameters;
    parser.Parse((SegmentFile)param.SegFile);
    e.Result = param;
}

private void parserBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //old code
    ParserWorkerParameters param = e.Result as ParserWorkerParameters;
    if (param.CallBack != null)
    {
        param.CallBack();
    }
}

答案 1 :(得分:1)

正如上面的评论中已经讨论过的,问题是你在调用WaitOne方法时阻塞了UI线程。您的BackgroundWorker实际上正在更新进度条的Value属性(通过执行此操作,使其无效),但是应该阻止执行控件实际绘制的线程等待事件

根据您的评论,您似乎关心的是如何使用不同参数启动工作人员,并根据这些参数以不同方式处理RunWorkerCompleted事件。

一种方法可能是为该事件附加不同的处理程序,无论何时从程序中的某个点启动worker:

// attach the handler
parserBackgroundWorker.RunWorkerCompleted += FirstCaseHandler;

// run it
parserBackgroundWorker.RunWorkerAsync(selectedSegFile);

在这种情况下,你的每个处理程序应该做的第一件事是分离自己:

void FirstCaseHandler(object sender, RunWorkerCompletedEventArgs e)
{
    // detach this specific handler
    parserBackgroundWorker.RunWorkerCompleted -= FirstCaseHandler;

    // do stuff
    ...
}

或者,您可以附加单个处理程序并使用它根据工作结果处理不同的情况。

在这种情况下,您可以设置Result的{​​{1}}属性,以便在DoWorkEventArgs方法完成后将生成的对象传递给处理程序:

DoWork

在这种情况下,您将检查void parserBackgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // do stuff var parserResult = parser.Parse((SegmentFile)e.Argument); // set the Result property with a custom object which // will allow you to know which case you need to handle // this can be simply: e.Result = e.Argument; // or, you can create an instance of your own class, something like: e.Result = new WorkerResult(e.Argument, parserResult); } 处理程序中e.Result的值:

RunWorkerCompleted

您甚至可以将回调委托作为参数传递,并从void parserBackgroundWorker_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { var resultInfo = e.Result as WorkerResult; // or whatever // do the right thing based on its value } 处理程序调用此方法,因此您确实有很多选项。