关于自定义通知事件的跨线程问题
2011-04-21 15:24
344 查看
[知识背景]
所谓自定义通知事件,就是指在自己的类中定义的事件,该事件用于向调用者发出通知。比如做一个下载工具,下载是需要时间的,用户在界面里点击“下载”之后,我的下载类在后台开启线程开始传输数据,前台界面上可以同时执行其他操作。当数据传输完成,需要通知界面(调用者)已完成下载,以便界面上做相应的改变。这就需要在我的下载类中有类似 DownloadCompleted 的事件,这样在用户的代码中可以通过 downloader.DownloadCompleted += new new EventHandler(XXXXX) 进入他自己的事件处理函数。
这里说的跨线程问题,是指非法的跨线程调用问题。还用上个例子,在下载完成时,需要改变界面中 Label 控件的 Text 属性以提示用户下载完成。这就牵涉到在另一个类所创建的线程中操纵UI线程中创建的控件。这种做法在 .NET 中是不推荐的,同时这样会严重影响代码质量。(可参考MSDN:ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_fxmclictl/html/138f38b6-1099-4fd5-910c-390b41cbad35.htm)
[案例]
自定义一个类似与 Timer 的控件,并实现一个 Tick 事件。调用者在 Tick 事件里操纵界面上的元素。
代码段:
Form1.cs 里的代码:
1 public Form1()
2 {
3 InitializeComponent();
4 MyTimer mytimer = new MyTimer();
5 mytimer.Tick += new EventHandler(mytimer_Tick);
6 mytimer.Start();
7 }
8
9 void mytimer_Tick(object sender, EventArgs e)
{
CheckBox check = new CheckBox();
check.Top = this.Controls.Count * check.Height;
this.Controls.Add(check);
}
MyTimer.cs 文件里的代码:
public event EventHandler Tick;
protected virtual void OnTick(EventArgs e)
{
if (Tick != null)
{
Tick(this, e);
}
}
public void Start()
{
if (_bRunning)
{
return;
}
_threadWork = new Thread(new ThreadStart(ThreadWork));
_threadWork.IsBackground = true;
_threadWork.Start();
}
public void Stop()
{
_threadWork.Abort();
_threadWork = null;
}
private void ThreadWork()
{
while (true)
{
OnTick(new EventArgs());
Thread.Sleep(_interval);
}
}
这种写法是MSDN里常用的一种,但是那里没有牵涉到跨线程调用。在这个案例下,这种做法就行不通了。调试时会报错。如图。
分析:
这里的 OnTick 事件是在Start()方法中创建的线程中调用的,在 OnTick 中调用了 Tick,由委托机制可知,等同于调用了 Form1.cs 中的 mytimer_Tick ,而mytimer_Tick 调用了 UI 上的东西,这时在 mytimer_Tick 中就会出现跨线程调用。
解决办法:
改写 OnTick 方法。使用 Invoke 机制来完成调用。
1 protected virtual void OnTick(EventArgs e)
2 {
3 if (Tick != null)
4 {
5 if (Tick.Target is System.ComponentModel.ISynchronizeInvoke)
6 {
7 System.ComponentModel.ISynchronizeInvoke aSynch = Tick.Target as System.ComponentModel.ISynchronizeInvoke;
8 if (aSynch.InvokeRequired)
9 {
object[] args = new object[2] {this, e };
aSynch.BeginInvoke(Tick, args);
}
else
{
Tick(this, e);
}
}
}
}
源代码下载:测试自定义通知事件的跨线程问题.rar
所谓自定义通知事件,就是指在自己的类中定义的事件,该事件用于向调用者发出通知。比如做一个下载工具,下载是需要时间的,用户在界面里点击“下载”之后,我的下载类在后台开启线程开始传输数据,前台界面上可以同时执行其他操作。当数据传输完成,需要通知界面(调用者)已完成下载,以便界面上做相应的改变。这就需要在我的下载类中有类似 DownloadCompleted 的事件,这样在用户的代码中可以通过 downloader.DownloadCompleted += new new EventHandler(XXXXX) 进入他自己的事件处理函数。
这里说的跨线程问题,是指非法的跨线程调用问题。还用上个例子,在下载完成时,需要改变界面中 Label 控件的 Text 属性以提示用户下载完成。这就牵涉到在另一个类所创建的线程中操纵UI线程中创建的控件。这种做法在 .NET 中是不推荐的,同时这样会严重影响代码质量。(可参考MSDN:ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_fxmclictl/html/138f38b6-1099-4fd5-910c-390b41cbad35.htm)
[案例]
自定义一个类似与 Timer 的控件,并实现一个 Tick 事件。调用者在 Tick 事件里操纵界面上的元素。
代码段:
Form1.cs 里的代码:
1 public Form1()
2 {
3 InitializeComponent();
4 MyTimer mytimer = new MyTimer();
5 mytimer.Tick += new EventHandler(mytimer_Tick);
6 mytimer.Start();
7 }
8
9 void mytimer_Tick(object sender, EventArgs e)
{
CheckBox check = new CheckBox();
check.Top = this.Controls.Count * check.Height;
this.Controls.Add(check);
}
MyTimer.cs 文件里的代码:
public event EventHandler Tick;
protected virtual void OnTick(EventArgs e)
{
if (Tick != null)
{
Tick(this, e);
}
}
public void Start()
{
if (_bRunning)
{
return;
}
_threadWork = new Thread(new ThreadStart(ThreadWork));
_threadWork.IsBackground = true;
_threadWork.Start();
}
public void Stop()
{
_threadWork.Abort();
_threadWork = null;
}
private void ThreadWork()
{
while (true)
{
OnTick(new EventArgs());
Thread.Sleep(_interval);
}
}
这种写法是MSDN里常用的一种,但是那里没有牵涉到跨线程调用。在这个案例下,这种做法就行不通了。调试时会报错。如图。
分析:
这里的 OnTick 事件是在Start()方法中创建的线程中调用的,在 OnTick 中调用了 Tick,由委托机制可知,等同于调用了 Form1.cs 中的 mytimer_Tick ,而mytimer_Tick 调用了 UI 上的东西,这时在 mytimer_Tick 中就会出现跨线程调用。
解决办法:
改写 OnTick 方法。使用 Invoke 机制来完成调用。
1 protected virtual void OnTick(EventArgs e)
2 {
3 if (Tick != null)
4 {
5 if (Tick.Target is System.ComponentModel.ISynchronizeInvoke)
6 {
7 System.ComponentModel.ISynchronizeInvoke aSynch = Tick.Target as System.ComponentModel.ISynchronizeInvoke;
8 if (aSynch.InvokeRequired)
9 {
object[] args = new object[2] {this, e };
aSynch.BeginInvoke(Tick, args);
}
else
{
Tick(this, e);
}
}
}
}
源代码下载:测试自定义通知事件的跨线程问题.rar
相关文章推荐
- 关于自定义通知事件的跨线程问题(转)
- 安卓关于自定义View只能接收ACTION_DOWN事件问题的解决
- 关于MKMapKit上的自定义callout view的事件响应问题
- 关于android通知栏图标自定义问题
- 关于UILocalNotification 的soundName问题(通知的自定义声音问题)
- 坑!!关于通知栏中支持自定义布局,不支持自定义控件的问题
- 关于线程并发访问全局变量问题
- Android 关于UI线程的问题
- 关于window.onclick事件的问题
- 关于SWT中线程的问题
- 关于Mysql5_1新特性 事件调度器(Event Scheduler) 的问题
- 关于jQuery的click事件不能触发的问题
- 关于浏览器滚动条自定义美化的若干问题
- 如果我是国王:关于解决 Java 编程语言线程问题的建议
- Cocos2dx Lua 关于Touch事件传递阻止下层传递的问题
- 关于iOS7之后自定义leftnavigationitem后手势无法响应问题的解决办法
- Axure RP Pro - 相关问题 - master主控文档的behavior行为是custom widget自定义部件时丢失raised event可触发事件
- java高级多线程编程(一)--关于线程的停止问题
- 关于Android 通知栏 兼容问题