我在我的应用程序中使用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();
答案 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
}
处理程序调用此方法,因此您确实有很多选项。