wpf研究之道-ProgressBar(进度条)控件
ProgressBar控件,非常有用。它在什么情况下有用呢?如何使用?带着这两个问题,我们探讨下。
如果程序需要很长时间来运行,用户在不知道的情况下,以为程序已经“卡死”了,没有响应,这时候就该用进度条了,它主动告诉用户的执行情况,那么用户知道还需要等待多久。
上面的使用场景,很好理解,那么,如何使用呢?
一边要执行长任务,一边还要不断地显示当前进度。这时候就得用多线程了,有人说那我就用单线程怎么了,那么咱们试一试便知道了。看如下的代码:
1 private void progressTest_Click(object sender, RoutedEventArgs e) 2 { 3 this.myBar.Minimum = 0; 4 this.myBar.Maximum = 1; 5 Computer(); 6 7 } 8 9 private void Computer() 10 { 11 for (int i = 1; i <= 100; i++) 12 { 13 var num = i; 14 15 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 16 (ThreadStart)delegate() 17 { 18 this.myBar.Value = num / (double)100; 19 20 }); 21 22 Thread.Sleep(100); 23 } 24 }
我们模拟了一个小循环,里面耗费一些时间,运行的过程,一直是这样的:
等程序运行完成后的结果:
换句话说,我们的进度条多此一举,没有起到进度变化的效果。我把程序改成多线程的:
1 private void progressTest_Click(object sender, RoutedEventArgs e) 2 { 3 this.myBar.Minimum = 0; 4 this.myBar.Maximum = 1; 5 6 7 Thread t = new Thread(() => 8 { 9 Computer(); 10 }); 11 t.Start(); 12 13 } 14 15 private void Computer() 16 { 17 for (int i = 1; i <= 100; i++) 18 { 19 var num = i; 20 21 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 22 (ThreadStart)delegate() 23 { 24 this.myBar.Value = num / (double)100; 25 26 }); 27 28 Thread.Sleep(100); 29 } 30 }
运行图如下:
为什么会出现这种情况?
一个人专心致志地做某件事情,如果中途不停地有人来打扰,是不是事情就没法做了呢。同理,如果当前的线程正在跑大任务,还要不停地刷新进度条。这个是不是很浪费执行的效率?所以我觉得从设计的角度理解,不允许单线程这样做。从第一组图中,就可以看出,单线程专心致志地做完事情后,才去更新界面。
公交车司机一边开车,到了某一站后,也不是亲自报站,而报站的任务落在了售票员身上,如果无售票员,那么司机按下系统按钮,让公交车上的报站设备去报。程序中往往运行大任务的是新开的另一个线程,此时主线程负责刷新界面,即刷新进度。