WPF中BackgroundWorker无法更新ProgressBar的问题排查
独立窗口ProgressBar不更新问题排查与解决
我需要实现一个独立窗口的ProgressBar,根据另一个窗体的长时处理进度更新。调试时DoWork和ProgressChanged事件都能正常触发,代码也能走到Worker_RunWorkerCompleted并关闭进度条窗口,但ProgressBar的UI完全没有更新。虽然知道WPF推荐用ViewModel,但已经简化代码尝试定位问题,确定是遗漏了某个简单细节,但一直没找到。
相关代码
XAML代码
<Window x:Class="CGXAcquisition.Forms.Dialog.FileProgressBar" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="File Upload Progress" Height="100" Width="300"> <Grid Margin="20"> <ProgressBar Minimum="0" Maximum="100" Name="pbStatus" /> <TextBlock Text="{Binding ElementName=pbStatus, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </Window>
进度条窗口后台代码
public partial class FileProgressBar : Window, INotifyPropertyChanged { BackgroundWorker worker = new BackgroundWorker(); private int fileLines = 0; private int totalFileLines = 0; public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } public int FileLines { get { return fileLines; } set { fileLines = value; Percentage = (int)Math.Round((double)fileLines / TotalFileLines); OnPropertyChanged("FileLines"); } } public int TotalFileLines { get { return totalFileLines; } set { totalFileLines = value; } } public int Percentage { get; set; } public FileProgressBar(int totalLines) { InitializeComponent(); TotalFileLines = totalLines; Loaded += Window_ContentRendered; } private void Window_ContentRendered(object sender, EventArgs e) { worker.WorkerReportsProgress = true; worker.WorkerSupportsCancellation = true; worker.DoWork += worker_DoWork; worker.RunWorkerCompleted += Worker_RunWorkerCompleted; worker.ProgressChanged += worker_ProgressChanged; worker.RunWorkerAsync(); } private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { this.Close(); } void worker_DoWork(object sender, DoWorkEventArgs e) { for(int i = 0; i < 100; i++) { Thread.Sleep(100); int percent = i / 100; worker.ReportProgress(percent, i); } } void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { pbStatus.Value = e.ProgressPercentage; } }
调用进度条的代码(另一窗体)
// 构造函数中绑定Loaded事件 Loaded += OnLoaded; private void OnLoaded(object sender, RoutedEventArgs e) { ShowProgressBar(); } private void ShowProgressBar() { progress = new FileProgressBar(FileInfo.LineCount); progress.Show(); }
问题根源与解决
最终定位到是进度百分比的计算错误:
原代码中DoWork里的计算:
int percent = i / 100;
这里是整数除法,当i取值0到99时,i/100的结果始终为0,导致ReportProgress传递的进度值一直是0,ProgressBar自然没有任何变化。
修正后的规范计算方式:
int percent = (int)((double)i / 100 * 100);
当然也可以直接用i作为进度值(因为循环范围刚好是0-99,对应0%-99%),但如果需要严格按比例计算进度,上述修正后的代码可以正确得到百分比数值。
内容的提问来源于stack exchange,提问作者nutz
相关产品推荐
相关产品推荐

