用Timer还是用BackgroundWorker实现定时更新画面的功能
标签:?timerobjectrandomstring工作class
2010-02-10 17:47?
974人阅读?
?
收藏?
举报
版权声明:本文为博主原创文章,未经博主允许不得转载。
第一次发文章,水平有限,如有错误欢迎大家指出。
?
声明:
1,测试环境为vs2008,?.net framework 3.5
2,此次我使用的Timer是?System.Windows.Forms 命名空间下的 Timer 组件,另外两个Timer我没试验。
3,我没有用工具箱添加Timer和BackgroundWorker
?
首先
介绍一下画面
总共有3个Form

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

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

?
?
两个画面很类似。
实现的是同一个功能。
?
主画面功能不详述。
?
先说第一个画面
?
[c-sharp]?
view plain
?copy
- using?System;??
- using?System.Windows.Forms;??
- namespace?TimerAndWorker??
- {??
- ??????
- ??????
- ///?运行时会出现画面假死??
- ///?</summary>??
- ????public?partial?class?FrmTimer?:?Form??
- ????{??
- ????????public?FrmTimer()??
- ????????{??
- ????????????InitializeComponent();??
- ????????}??
- ????????#region?"变量定义"??
- ????????private?System.Windows.Forms.Timer?timer;??
- ????????Random?rd;??
- ????????#endregion??
- ????????#region?"Timer相关的内容"??
- ??????????
- ??????????
- private?void?InitTimer()??
- ????????????Console.WriteLine("进入?InitTimer");??
- ????????????this.timer?=?new?System.Windows.Forms.Timer();??
- ????????????this.timer.Interval?=?5000;??
- this.timer.Tick?+=?new?System.EventHandler(this.timer1_Tick);??
- this.timer.Start();??
- ????????????Console.WriteLine("走出?InitTimer");??
- ????????}??
- ///?Timer每隔一定时间将会让画面执行一次这个方法??
- ///?<param?name="sender"></param>??
- ///?<param?name="e"></param>??
- void?timer1_Tick(object?sender,?EventArgs?e)??
- ????????????Console.WriteLine("进入?timer1_Tick");??
- this.UseWaitCursor?=?true;??
- ??????????????
- ??????????????
- ????????????Console.WriteLine("开始忙碌");??
- //?画面将会出现假死现象??
- ????????????System.Threading.Thread.Sleep(3000);??
- ????????????Console.WriteLine("停止忙碌");??
- foreach?(DataGridViewRow?row?in?dataGridView1.Rows)??
- ????????????{??
- ????????????????if?(rd.Next(1,?100)?%?2?==?0)??
- ????????????????{??
- ????????????????????row.Cells["columnStatus"].Value?=?"连接";??
- ????????????????}??
- else??
- ????????????????????row.Cells["columnStatus"].Value?=?"断开";??
- ????????????}??
- false;??
- ????????????Console.WriteLine("走出?timer1_Tick");??
- ????????#endregion??
- ????????#region?"与Form有关的内容"??
- //?定义了一个产生随机数的对象??
- //?目的是为了随机生成画面上的状态??
- ??
- ///?Form的Load事件??
- void?FrmTimer_Load( ????????????Console.WriteLine("进入?FrmTimer_Load");??
- ????????????InitDataGridView();??
- ????????????InitTimer();??
- //?给随机数一个种子??
- ????????????rd?=?new?Random(DateTime.Now.Millisecond);??
- ????????????Console.WriteLine("走出?FrmTimer_Load");??
- ///?给画面上的DataGridView赋初值??
- void?InitDataGridView()??
- ????????????Console.WriteLine("进入?InitDataGridView");??
- for?(Int32?i?=?1;?i?<?6;?i++)??
- ????????????{??
- ????????????????dataGridView1.Rows.Add(new?String[]?{?"192.168.1."?+?i.ToString(),?"断开"?});??
- ????????????Console.WriteLine("走出?InitDataGridView");??
- ///?关闭画面??
- void?btnClose_Click( ????????????Console.WriteLine("进入?btnClose_Click");??
- this.Close();??
- ????????????Console.WriteLine("走出?btnClose_Click");??
- ///?画面关闭时??
- ///?</summary>??
- ///?<param?name="sender"></param>??
- ///?<param?name="e"></param>??
- void?FrmTimer_FormClosing( ????????{??
- ????????????Console.WriteLine("进入?FrmTimer_FormClosing");??
- ????????????timer.Stop();??
- ????????????Console.WriteLine("走出?FrmTimer_FormClosing");??
- ???
- ????}??
- }??
?
?
利用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??
- 进入?InitDataGridView??
- 走出?InitDataGridView??
- 进入?InitTimer??
- 走出?InitTimer??
- 走出?FrmTimer_Load??
- 进入?timer1_Tick??
- 开始忙碌??
- 停止忙碌??
- 走出?timer1_Tick??
- 进入?btnClose_Click??
- 进入?FrmTimer_FormClosing??
- 走出?FrmTimer_FormClosing??
- 走出?btnClose_Click??
?
?
在每次出现?“开始忙碌” 的时候画面开始假死,鼠标点击画面没反应。停止忙碌时恢复。
?
?
我们再来看看BackgroundWorker的表现
?
代码如下
?
[c-sharp]
view plain
copy
using?System.ComponentModel;??
- using?System.Windows.Forms;??
- namespace?TimerAndWorker??
- {??
- ///?BackgroundWorker示例??
- ///?运行时不会出现画面假死??
- ????class?FrmWorker?:?Form??
- ????{??
- public?FrmWorker()??
- ????????????InitializeComponent();??
- ????????#region?"Worker"??
- //?定义一个BackgroundWorker??
- ????????BackgroundWorker?worker;??
- ///?初始化worker??
- void?InitWorker()??
- ????????????Console.WriteLine("进入?InitWorker");??
- //?实例化??
- ????????????worker?=?new?BackgroundWorker();??
- //?给worker指派他要干的活??
- ????????????worker.DoWork?+=?new?DoWorkEventHandler(worker_DoWork);??
- ??????????????
- //?给worker添加回调??
- ????????????worker.RunWorkerCompleted?+=?new?RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);??
- ??????????????
- //?让worker支持取消??
- ????????????worker.WorkerSupportsCancellation?=?//?让worker去干活??
- ????????????worker.RunWorkerAsync();??
- ????????????Console.WriteLine("走出?InitWorker");??
- ///?Worker工作完成时的回调函数??
- void?worker_RunWorkerCompleted( ????????????Console.WriteLine("进入?worker_RunWorkerCompleted");??
- //?当worker结束的时候就是画面停止刷新的时候??
- //?所以worker结束时关闭画面??
- this.Close();??
- ????????????Console.WriteLine("走出?worker_RunWorkerCompleted");??
- ///?Worker要干的工作??
- void?worker_DoWork( ????????????Console.WriteLine("进入?worker_DoWork");??
- while?((sender?as?BackgroundWorker).CancellationPending?==?false)??
- ??????????????????
- ????????????????Console.WriteLine("开始忙碌");??
- //?这里并不会出现画面的假死??
- ????????????????System.Threading.Thread.Sleep(3000);??
- ????????????????Console.WriteLine("停止忙碌");??
- ??????????????????
- ????????????????in?dataGridView1.Rows)??
- ????????????????{??
- ???????????????????? ????????????????????{??
- ????????????????????????row.Cells["columnStatus"].Value?=?"连接";??
- ????????????????????}??
- else??
- ????????????????????????row.Cells["columnStatus"].Value?=?"断开";??
- ????????????Console.WriteLine("走出?worker_DoWork");??
- ????????#region?"与Form有关的内容"??
- //?定义了一个产生随机数的对象??
- //?目的是为了随机生成画面上的状态??
- ????????Random?rd;??
- void?FrmWorker_Load( ????????????Console.WriteLine("进入?FrmWorker_Load");??
- ????????????InitWorker();??
- ????????????Console.WriteLine("走出?FrmWorker_Load");??
- ///?点击关闭按钮时候??
- //?让worker取消当前任务??
- //?worker结束时就会关画面??
- ????????????worker.CancelAsync();??
- true;??
- this.Visible?=?void?FrmWorker_FormClosing( ????????????Console.WriteLine("进入?FrmWorker_FormClosing");??
- if?(worker.IsBusy)??
- //?如果worker正在忙则应该取消本次关闭画面的动作??
- ????????????????e.Cancel?=?//?等待worker关闭当前画面??
- ????????????????worker.CancelAsync();??
- false;??????????????????
- ????????????}??
- ????????????Console.WriteLine("走出?FrmWorker_FormClosing");??
- }??
?
由于backgroundworker是后台线程,所以不会出现画面假死现象。即便是
耗时操作
System.Threading.Thread.Sleep(3000);
也不会假死
所以。我建议如果有类似功能要实现的朋友要优先选择BackgroundWorker
这样可以让你的程序界面更灵活。
?
?
?
顺便提一句
====================================================================
以下的文字全是个人理解,很有可能与事实有偏差,欢迎指正。
====================================================================
如果说Form是一个线程,BackgroundWorker是另外一个线程。Form中的控件有可能会被禁止在BackgroundWorker的
Dowork中调用,这种调用被称为跨线程调用。如果出现这样的问题。请尝试下面的方法。
?
DataGridView.CheckForIllegalCrossThreadCalls = true;
?
DataGridView这里用的是类名而不是对象的引用
?
CheckForIllegalCrossThreadCalls?是 Control 类的成员
?
?
Control.?CheckForIllegalCrossThreadCalls
MSDN上的说明是:获取或设置一个值,该值指示是否捕获对错误线程的调用,这些调用在调试应用程序时访问控件的?Handle?属性。
?
?
改变CheckForIllegalCrossThreadCalls 的值,则可以让控件可以被跨线程操作。
? (编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|