将 DispatcherTimer 与 BackgroundWorker 和 ProgressBar 一起使用
Using DispatcherTimer with a BackgroundWorker and a ProgressBar
我创建了一个简单的应用程序,它每秒向 ListView 添加 10 次字符串并显示它。所有这些都是使用 BackgroundWorker 和显示添加进度的 ProgressBar 完成的。我的问题是,因为我听说暂停线程非常危险并且会导致几个问题,所以我如何用比方说 DispatcherTimer 替换 Thread.Sleep?
如果我向这个列表添加 1000000 个元素并报告进度怎么办?在这种情况下使用 Thread.Sleep(1) 还是其他更好?
我的代码如下:
private BackgroundWorker worker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
}
private void btnAggiungi_Click(object sender, RoutedEventArgs e)
{
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
String text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
int min;
int max = 10;
for (min = 1; min <= max; min++)
{
int progressPercentage = Convert.ToInt32((double)min / max * 100);
worker.ReportProgress(progressPercentage, text);
Thread.Sleep(100);
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pb.Value = e.ProgressPercentage;
lstLoremIpsum.Items.Add(e.UserState.ToString());
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblCompleted.Content = "Done";
}
截图:
经过一些测试:
worker.ReportProgress的意思是将BackgroundWorker的整体进度反馈给UI线程。这样您就可以显示进度并通知您的用户。但是,您正在使用它实际将字符串添加到列表框/列表视图。您最好在内存中(列表/数组中的缓冲区)编译添加字符串(文本),然后在后台工作人员完成时填充列表框/列表视图一次。如果您的 GUI 仍然冻结,请添加每 50、100 或 200 的字符串。
还有另一个小改进:
private void UpdateProgressbar(int percentage)
{
if (InvokeRequired)
{
this.BeginInvoke(new Action<int>(UpdateProgressbar), new object[] { percentage });
return;
}
pb.Value = percentage;
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UpdateProgressbar(e.ProgressPercentage);
}
我创建了一个简单的应用程序,它每秒向 ListView 添加 10 次字符串并显示它。所有这些都是使用 BackgroundWorker 和显示添加进度的 ProgressBar 完成的。我的问题是,因为我听说暂停线程非常危险并且会导致几个问题,所以我如何用比方说 DispatcherTimer 替换 Thread.Sleep? 如果我向这个列表添加 1000000 个元素并报告进度怎么办?在这种情况下使用 Thread.Sleep(1) 还是其他更好?
我的代码如下:
private BackgroundWorker worker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
}
private void btnAggiungi_Click(object sender, RoutedEventArgs e)
{
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
String text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
int min;
int max = 10;
for (min = 1; min <= max; min++)
{
int progressPercentage = Convert.ToInt32((double)min / max * 100);
worker.ReportProgress(progressPercentage, text);
Thread.Sleep(100);
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pb.Value = e.ProgressPercentage;
lstLoremIpsum.Items.Add(e.UserState.ToString());
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblCompleted.Content = "Done";
}
截图:
经过一些测试:
worker.ReportProgress的意思是将BackgroundWorker的整体进度反馈给UI线程。这样您就可以显示进度并通知您的用户。但是,您正在使用它实际将字符串添加到列表框/列表视图。您最好在内存中(列表/数组中的缓冲区)编译添加字符串(文本),然后在后台工作人员完成时填充列表框/列表视图一次。如果您的 GUI 仍然冻结,请添加每 50、100 或 200 的字符串。
还有另一个小改进:
private void UpdateProgressbar(int percentage)
{
if (InvokeRequired)
{
this.BeginInvoke(new Action<int>(UpdateProgressbar), new object[] { percentage });
return;
}
pb.Value = percentage;
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UpdateProgressbar(e.ProgressPercentage);
}