先看这样的一个例子: 点击"多线程访问"按钮标签中文本"此标签被另一个线程设置文本"会变为"Hello"! 代码是这样写的: /// <summary> /// 设置标签的文本 /// </summary> private void SetLableText() { this.label1.Text = "Hello!"; } /// <summary> /// 设置标签的按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { System.Threading.Thread setLabelTextThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.SetLableText)); setLabelTextThread.Start(); } 按照想法,这个功能是完成了,运行.点击按钮,却出现了异常: 分析:label标签控件是主线程创建的,不能直接从另一个线程访问.可以这样认为:不能跨线程直接访问控件; 如何才能实现这个功能呢? 在.NET中,所有的控件都是从System.Windows.Forms.Control类派生,Control类提供了一个Invoke()方法,用于在创建控件的线程中访问线程.它的定义如下: public Object Invoke(Delegate method); 它的参数为一个委托,代表创建控件的线程中要执行的方法. 可以利用这个方法来实现这个功能. 首先定义一个委托: public delegate void setLabelTextDelegate();//定义一个setLabelTextDelegate()的委托 在定义一个委托变量: private setLabelTextDelegate setLabelText; 在窗体的构造函数中给这个委托变量初始化: public Form1() { InitializeComponent(); this.setLabelText = this.SetLableText;//SetLableText为上面的"设置标签的文本"的方法 } 然后在定义一个方法.方法里使用Invoke private void ThreadMethod() { this.label1.Invoke(this.setLabelText);//setLabelText为上面定义的委托变量 } 接着把按钮事件里的代码修改一下: /// <summary> /// 设置标签的按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { System.Threading.Thread setLabelTextThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.SetLableText));//这个方法修改为ThreadMethod,即: // System.Threading.Thread setLabelTextThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.ThreadMethod)); setLabelTextThread.Start(); } 这个就OK了,运行.点击: 功能实现:
不过"设置标签的文本"的方法SetLableText()是没有参数的,在很多情况下,我们写的方法都是需要参数的,下面我就把这个例子改成有参数的,并演示如何传递参数: 首先:改造"设置标签的文本"的方法SetLableText()变成有参数的: /// <summary> /// 设置标签的文本 /// </summary> private void SetLableText(string info) { this.label1.Text = info; } 既然这个方法有参数了,与它对应的委托应该使用参数: public delegate void setLabelTextDelegate(string infor); 定义的委托变量还是在构造函数中初始化,这个不用改变什么: public Form1() { InitializeComponent(); this.setLabelText = this.SetLableText; } 既然使用了参数,那么Invoke()这个方法应该会有重载的方法吧? 对Invoke()这个方法是有重载的,它的定义如下: public Object Invoke(Delegate method,param Object [] args); 第二个参数是一个object的数组,就意味着,可以把需要传递的参数放到这个数组里面来进行传递 对ThreadMethod()改造: private void ThreadMethod(Object info) { this.label1.Invoke(this.setLabelText, new object[] { info}); } 注意红色部分,为添加的参数 最后是按钮事件的改造了: /// <summary> /// 设置标签的按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button1_Click(object sender, EventArgs e) { System.Threading.Thread setLabelTextThread = new System.Threading.Thread(this.ThreadMethod); setLabelTextThread.Start("Hello!"); } 改造成功: 跨线程访问控件步骤可以总结一下: (1)将访问的控件代码封装为一个方法; (2)根据方法自定义一个对应委托; (3)增加一个定义的委托类型的字段,并把前面访问控件的方法"挂接"到此字段中; (4)编写一个线程方法,在此方法中调用要访问控件的Invoke方法,并把定义好了的委托字段做为参数传入. (5)在合适的地方创建线程并启动运行 本人的第一篇博文.所写的都是雕虫小技,不足挂齿.只是希望把自己的心得分享出来.
昵称: [登录] [注册]
主页:
邮箱:(仅博主可见)
验证码: 看不清,换一个
评论内容:
登录 注册
[使用Ctrl+Enter键快速提交评论]