微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用Timer还是用BackgroundWorker实现定时更新画面的功能

用Timer还是用BackgroundWorker实现定时更新画面的功能

标签: timerobjectrandomstring工作class
  974人阅读  评论(0)  收藏  举报

第一次发文章,水平有限,如有错误欢迎大家指出。

 

声明:

1,测试环境为vs2008, .net framework 3.5

2,此次我使用的Timer是 System.Windows.Forms 命名空间下的 Timer 组件,另外两个Timer我没试验。

3,我没有用工具箱添加Timer和BackgroundWorker

 

首先

介绍一下画面

总共有3个Form

主画面

 

点击第一个图标弹出下面的画面

 

Timer画面

 

点击第二个图标弹出下面的画面

 

BackgroundWorker

 

 

两个画面很类似。

实现的是同一个功能

 

主画面功能不详述。

 

先说第一个画面

 

[c-sharp]  view plain  copy
  1. using System;  
  2. using System.Windows.Forms;  
  3. namespace TimerAndWorker  
  4. {  
  5.     /// <summary>  
  6.     /// System.Windows.Forms.Timer示例  
  7. /// 运行时会出现画面假死  
  8. /// </summary>  
  9.     public partial class FrmTimer : Form  
  10.     {  
  11.         public FrmTimer()  
  12.         {  
  13.             InitializeComponent();  
  14.         }  
  15.         #region "变量定义"  
  16.         private System.Windows.Forms.Timer timer;  
  17.         Random rd;  
  18.         #endregion  
  19.         #region "Timer相关的内容"  
  20.         /// <summary>  
  21.         /// 初始化Timer  
  22. private void InitTimer()  
  23.             Console.WriteLine("进入 InitTimer");  
  24.             this.timer = new System.Windows.Forms.Timer();  
  25.             this.timer.Interval = 5000;  
  26. this.timer.Tick += new System.EventHandler(this.timer1_Tick);  
  27. this.timer.Start();  
  28.             Console.WriteLine("走出 InitTimer");  
  29.         }  
  30. /// Timer每隔一定时间将会让画面执行一次这个方法  
  31. /// <param name="sender"></param>  
  32. /// <param name="e"></param>  
  33. void timer1_Tick(object sender, EventArgs e)  
  34.             Console.WriteLine("进入 timer1_Tick");  
  35. this.UseWaitCursor = true;  
  36.             // 假设这个时候有比较耽误时间的操作  
  37.             // 此处我用Sleep来代替  
  38.             Console.WriteLine("开始忙碌");  
  39. // 画面将会出现假死现象  
  40.             System.Threading.Thread.Sleep(3000);  
  41.             Console.WriteLine("停止忙碌");  
  42. foreach (DataGridViewRow row in dataGridView1.Rows)  
  43.             {  
  44.                 if (rd.Next(1, 100) % 2 == 0)  
  45.                 {  
  46.                     row.Cells["columnStatus"].Value = "连接";  
  47.                 }  
  48. else  
  49.                     row.Cells["columnStatus"].Value = "断开";  
  50.             }  
  51. false;  
  52.             Console.WriteLine("走出 timer1_Tick");  
  53.         #endregion  
  54.         #region "与Form有关的内容"  
  55. // 定义了一个产生随机数的对象  
  56. // 目的是为了随机生成画面上的状态  
  57.   
  58. /// Form的Load事件  
  59. void FrmTimer_Load(             Console.WriteLine("进入 FrmTimer_Load");  
  60.             InitDataGridView();  
  61.             InitTimer();  
  62. // 给随机一个种子  
  63.             rd = new Random(DateTime.Now.Millisecond);  
  64.             Console.WriteLine("走出 FrmTimer_Load");  
  65. /// 给画面上的DataGridView赋初值  
  66. void InitDataGridView()  
  67.             Console.WriteLine("进入 InitDataGridView");  
  68. for (Int32 i = 1; i < 6; i++)  
  69.             {  
  70.                 dataGridView1.Rows.Add(new String[] { "192.168.1." + i.ToString(), "断开" });  
  71.             Console.WriteLine("走出 InitDataGridView");  
  72. /// 关闭画面  
  73. void btnClose_Click(             Console.WriteLine("进入 btnClose_Click");  
  74. this.Close();  
  75.             Console.WriteLine("走出 btnClose_Click");  
  76. /// 画面关闭  
  77. /// </summary>  
  78. /// <param name="sender"></param>  
  79. /// <param name="e"></param>  
  80. void FrmTimer_FormClosing(         {  
  81.             Console.WriteLine("进入 FrmTimer_FormClosing");  
  82.             timer.Stop();  
  83.             Console.WriteLine("走出 FrmTimer_FormClosing");  
  84.    
  85.     }  
  86. }  
 

 

利用Timer的实现机制实际上是事件(event)机制

 

this.timer.Tick += new System.EventHandler(this.timer1_Tick);

这一行代码是让Timer在指定时间触发一个事件

而画面定义一个方法

private void timer1_Tick(object sender,EventArgs e)

对此事件进行响应。

 

此响应方法是Form的线程去执行的方法,所以,在此方法内执行很耗时的操作时。画面将会出现假死现象。

 

例如:读数据库或者进行网络连接以及复杂运算等等。

本例采用

System.Threading.Thread.Sleep(3000);

来代替耗时操作。实际运行时出现画面没响应的现象,具体现象请下载代码实践一下。

以下是执行时输出的日志

 

copy
    进入 FrmTimer_Load  
  1. 进入 InitDataGridView  
  2. 走出 InitDataGridView  
  3. 进入 InitTimer  
  4. 走出 InitTimer  
  5. 走出 FrmTimer_Load  
  6. 进入 timer1_Tick  
  7. 开始忙碌  
  8. 停止忙碌  
  9. 走出 timer1_Tick  
  10. 进入 btnClose_Click  
  11. 进入 FrmTimer_FormClosing  
  12. 走出 FrmTimer_FormClosing  
  13. 走出 btnClose_Click  
 

 

在每次出现 “开始忙碌” 的时候画面开始假死,鼠标点击画面没反应。停止忙碌时恢复。

 

 

我们再来看看BackgroundWorker的表现

 

代码如下

 

[c-sharp] view plain copy
    using System.ComponentModel;  
  1. using System.Windows.Forms;  
  2. namespace TimerAndWorker  
  3. {  
  4. /// BackgroundWorker示例  
  5. /// 运行时不会出现画面假死  
  6.     class FrmWorker : Form  
  7.     {  
  8. public FrmWorker()  
  9.             InitializeComponent();  
  10.         #region "Worker"  
  11. // 定义一个BackgroundWorker  
  12.         BackgroundWorker worker;  
  13. /// 初始化worker  
  14. void InitWorker()  
  15.             Console.WriteLine("进入 InitWorker");  
  16. // 实例化  
  17.             worker = new BackgroundWorker();  
  18. // 给worker指派他要干的活  
  19.             worker.DoWork += new DoWorkEventHandler(worker_DoWork);  
  20.               
  21. // 给worker添加回调  
  22.             worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);  
  23.               
  24. // 让worker支持取消  
  25.             worker.WorkerSupportsCancellation = // 让worker去干活  
  26.             worker.RunWorkerAsync();  
  27.             Console.WriteLine("走出 InitWorker");  
  28. /// Worker工作完成时的回调函数  
  29. void worker_RunWorkerCompleted(             Console.WriteLine("进入 worker_RunWorkerCompleted");  
  30. // 当worker结束的时候就是画面停止刷新的时候  
  31. // 所以worker结束时关闭画面  
  32. this.Close();  
  33.             Console.WriteLine("走出 worker_RunWorkerCompleted");  
  34. /// Worker要干的工作  
  35. void worker_DoWork(             Console.WriteLine("进入 worker_DoWork");  
  36. while ((sender as BackgroundWorker).CancellationPending == false)  
  37.                 // 假设这里是很漫长的工作  
  38.                 Console.WriteLine("开始忙碌");  
  39. // 这里并不会出现画面的假死  
  40.                 System.Threading.Thread.Sleep(3000);  
  41.                 Console.WriteLine("停止忙碌");  
  42.                 // 更改画面状态  
  43.                 in dataGridView1.Rows)  
  44.                 {  
  45.                                          {  
  46.                         row.Cells["columnStatus"].Value = "连接";  
  47.                     }  
  48. else  
  49.                         row.Cells["columnStatus"].Value = "断开";  
  50.             Console.WriteLine("走出 worker_DoWork");  
  51.         #region "与Form有关的内容"  
  52. // 定义了一个产生随机数的对象  
  53. // 目的是为了随机生成画面上的状态  
  54.         Random rd;  
  55. void FrmWorker_Load(             Console.WriteLine("进入 FrmWorker_Load");  
  56.             InitWorker();  
  57.             Console.WriteLine("走出 FrmWorker_Load");  
  58. /// 点击关闭按钮时候  
  59. // 让worker取消当前任务  
  60. // worker结束时就会关画面  
  61.             worker.CancelAsync();  
  62. true;  
  63. this.Visible = void FrmWorker_FormClosing(             Console.WriteLine("进入 FrmWorker_FormClosing");  
  64. if (worker.IsBusy)  
  65. // 如果worker正在忙则应该取消本次关闭画面的动作  
  66.                 e.Cancel = // 等待worker关闭当前画面  
  67.                 worker.CancelAsync();  
  68. false;                  
  69.             }  
  70.             Console.WriteLine("走出 FrmWorker_FormClosing");  
  71. }  

 

由于backgroundworker是后台线程,所以不会出现画面假死现象。即便是

耗时操作

System.Threading.Thread.Sleep(3000);

也不会假死

所以。我建议如果有类似功能要实现的朋友要优先选择BackgroundWorker

这样可以让你的程序界面更灵活。

 

 

 

顺便提一句

====================================================================

以下的文字全是个人理解,很有可能与事实有偏差,欢迎指正。

====================================================================

如果说Form是一个线程,BackgroundWorker是另外一个线程。Form中的控件有可能会被禁止在BackgroundWorker的

Dowork中调用,这种调用被称为跨线程调用。如果出现这样的问题。请尝试下面的方法

 

DataGridView.CheckForIllegalCrossthreadCalls = true;

 

DataGridView这里用的是类名而不是对象的引用

 

CheckForIllegalCrossthreadCalls 是 Control 类的成员

 

 

Control. CheckForIllegalCrossthreadCalls

MSDN上的说明是:获取或设置一个值,该值指示是否捕获对错误线程的调用,这些调用在调试应用程序时访问控件的 Handle 属性

 

 

改变CheckForIllegalCrossthreadCalls 的值,则可以让控件可以被跨线程操作。

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐