[知识背景]

所谓自定义通知事件,就是指在自己的类中定义的事件,该事件用于向调用者发出通知。比如做一个下载工具,下载是需要时间的,用户在界面里点击“下载”之后,我的下载类在后台开启线程开始传输数据,前台界面上可以同时执行其他操作。当数据传输完成,需要通知界面(调用者)已完成下载,以便界面上做相应的改变。这就需要在我的下载类中有类似 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)
10         {
11 
12             CheckBox check = new CheckBox();
13             check.Top = this.Controls.Count * check.Height;
14             this.Controls.Add(check);
15         }

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                     {
10                         object[] args = new object[2] {this, e };
11                         aSynch.BeginInvoke(Tick, args);
12                     }
13                     else
14                     {
15                         Tick(this, e);
16                     }
17                 }
18             }
19         }

源代码下载:测试自定义通知事件的跨线程问题.rar

转载于:https://www.cnblogs.com/bluebird2008/archive/2011/04/21/2023648.html

关于自定义通知事件的跨线程问题相关推荐

  1. ios跨线程通知_iOS多线程开发(三)---Run Loop(一)

    Run Loop Run Loop就是一个事件处理的循环,用来不停的调动工作以及处理输入事件.使用Run Loop的目的就是节省CPU效率,线程在有工作的时候忙于工作,而没工作的时候处于休眠状态. 一 ...

  2. ios跨线程通知_iOS多线程编程指南(三)Run Loop

    Run loops是线程相关的的基础框架的一部分.一个run loop就是一个事件处理的循环,用来不停的调度工作以及处理输入事件.使用run loop的目的是让你的线程在有工作的时候忙于工作,而没工作 ...

  3. ios跨线程通知_一种基于Metal、Vulkan多线程渲染能力的渲染架构

    快手Y-tech  原创最新技术干货分享 随着3D渲染场景规模越来越复杂,单线程渲染架构在满足业务性能要求时已经捉襟见肘,因此,多线程渲染显得愈发重要.本文首先介绍了新一代图形渲染接口Metal.Vu ...

  4. C#【委托/事件篇】跨线程访问窗体控件的方法

    文章目录 一.直接调用方法,方法中使用委托[textBox1.InvokeRequired] 二.调用委托,委托进一步关联方法 1.使用委托[最基础的调用方法:委托五步法] 2.使用Action作为委 ...

  5. C#中利用委托实现多线程跨线程操作

    在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常.这是微软为了保证线程安全以及提高代码的效率所做的改进,但是也给大家带来很多不便. 其实解决这个 ...

  6. jmeter多用户登录跨线程组操作传值

    项目需求: 需要登录两个用户A.B,用户A操作完后会通知B,然后B再操作,B操作完结束或者再通知A. 实现思路: 1. 设置两个线程组Ⅰ.Ⅱ,组Ⅰ添加cookie管理器,里面添加用户A的操作:组Ⅱ添加 ...

  7. C# 学习笔记(8) 控件的跨线程访问

    C# 学习笔记(8) 控件的跨线程访问 本文参考博客 C#多线程 https://www.cnblogs.com/dotnet261010/p/6159984.html C# 线程与进程 https: ...

  8. connect跨进程 qt_编写 Qt 跨线程异步调用器

    本文使用 Zhihu On VSCode 创作并发布 本文使用 CC BY-NC-SA 4.0 许可协议,转载请注明来源 一.设计背景 众所周知,Qt 的信号槽系统提供了线程安全的跨线程异步执行代码的 ...

  9. 跨线程操作无效:从创建该线程的线程以外的线程访问控件

    我有一个场景. (Windows窗体,C#.. NET) 有一个主窗体可以承载一些用户控件. 用户控件执行一些繁重的数据操作,因此,如果我直接调用UserControl_Load方法,则UI在加载方法 ...

  10. ZeroMq实现跨线程通信

    ZeroMq实现跨线程通信 之前在技术崇拜的技术经理指导下阅读了ZeroMq的基础代码,现在就将阅读的心得与成果记录一下,并重新模仿实现了一下经理的异步队列. 1.对外接口 //主要接口(1)void ...

最新文章

  1. 最新成果被AAAI-20收录,腾讯安全科恩实验室加快AI产业化应用
  2. 面向对象理论(6)-Interface Programming-[A]
  3. MUI多端发布开发指南(终于把MUI的使用场景说清楚了)
  4. Kafka的基本介绍和在linux的安装配置
  5. 用 Python 告诉你!最近 24 小时内朋友圈发生了什么
  6. jvm配置参数,查看大对象直接分配到老年代
  7. 又论社区风气, 与程序员是干嘛地的.
  8. [Hands On ML] 6. 决策树
  9. 运行报错:java.io.IOException: invalid constant type: 15
  10. 鸿蒙硬件HI3861-OLED扫雷版本1
  11. html5光标进去默认值消失,html点击input没有出现光标怎么办
  12. micropython stm32f429_[MicroPython]STM32F407开发板控制BMP180测量气压
  13. 如何抓取html请求,网页抓取工具如何进行http模拟请求
  14. 十八个经典问答,讲透了RS485接口!-小白收藏
  15. 基于TI Sitara系列AM3352/AM3354/AM3359的Linux常用开发案例分享
  16. python求均值函数_python求列表平均值函数
  17. websocket断开重连解决方案,基于子慕大诗人博客修改 健壮强化版
  18. 【Web】Excle题库抽题组卷在jsp显示
  19. seo和sem有什么关系
  20. ZOC7 for Mac(终端仿真器)

热门文章

  1. Ubuntu16.04安装VirtualBox及无法启动的解决办法
  2. 想起“不能什么都是你来干”
  3. vs 配置 .pdb
  4. java的睡眠方式有几种_java的几种定时任务
  5. centos php7.0 mysql,如何在centos7.3系统下安装php7.0
  6. PHP图片水印右下角,php图片水印处理
  7. 3G dual band 使用策略
  8. 十二周二次课 12.6 Nginx安装 12.7 默认虚拟主机 12.8 Nginx用户认证 12.
  9. centos修改jdk之后无法生效问题
  10. 三层代码的bll dal 层优化