我有一个ProgressBarWindow,它上面有一个进度条和一个取消按钮,用于报告文件I / O的进度。但是,尽管在后台工作中完成了所有工作,但ProgressBarWindow的UI线程和我的主窗口都会挂起。进度条呈现,就像我的主窗口一样,但是在后台工作人员执行其操作时不会更新。 在主窗口的构造函数的最后调用以下代码:
iCountLogLinesProgressBar = new ProgressBarWindow();
iCountLogLinesProgressBar.cancelButton.Click += EventCountLogLinesProgressBarCancelButtonClicked;
iCountLogLinesProgressBar.Show();
iCountLogRecords = new BackgroundWorker();
iCountLogRecords.DoWork += EventCountLogLinesDoWork;
iCountLogRecords.ProgressChanged += EventCountLogLinesProgressChanged;
iCountLogRecords.RunWorkerCompleted += EventCountLogLinesRunWorkerCompleted;
iCountLogRecords.WorkerReportsProgress = true;
iCountLogRecords.WorkerSupportsCancellation = true;
iCountLogRecords.RunWorkerAsync(new BinaryReader(File.Open(iMainLogFilename, FileMode.Open, FileAccess.Read)));
EventCountLogLinesProgressChanged()如下所示:
private void EventCountLogLinesProgressChanged(object sender, ProgressChangedEventArgs e)
{
iCountLogLinesProgressBar.Value = e.ProgressPercentage;
}
这是ProgressBarWindow的缩短版本(其余只是几个制定者):
public partial class ProgressBarWindow : Window
{
public ProgressBarWindow()
{
InitializeComponent();
this.progressBar.Value = this.progressBar.Minimum = 0;
this.progressBar.Maximum = 100;
}
public double Value
{
get
{
return progressBar.Value;
}
set
{
this.progressBar.Value = value;
}
}
}
我已经尝试在dispatcher.invoke委托中包装值setter行但是这给了我一个堆栈溢出(我不应该有一个dispatcher.invoke行,因为backgroundworker在UI Thread中调用ProgressChanged,对吧? )。我已经检查了msdn并用谷歌搜索了但我似乎无法找到其他任何有这个问题的人。
编辑道歉,我没有意识到我的简化代码阻止了UI线程,尽管使用了后台工作者,但我得到了完全相同的行为,所以我错误地认为它们是等效的。我应该提到我正在使用背景工作者:P
答案 0 :(得分:14)
您正在阻止UI线程,因此在循环完成之前它不会重新呈现UI。
将后台处理移动到单独的线程中,并使用适当的Dispatcher
调用(或BackgroundWorker
)将UI更新调用封送回UI线程。
如果您的进度条确实只是一个计时器,您可以使用其中一个Timer
类来更新它。
答案 1 :(得分:3)
听Jon Skeet, 或者您有时可以调用Application.DoEvents()在同一个线程中进行所有UI更新。