跨线程调用Windows窗体控件[FreeDownload]

如对线程的操作不正确,在跨线程调用Windows窗体控件时会有产生InvalidOperationException异常。
该异常提示[线程间操作无效: 从不是创建控件“listBox1”的线程访问它.]。

我相信很多人通过设置Control.CheckForIllegalCrossThreadCalls属性为false禁止捕获对错误线程的调用。
这种强制性的禁止捕获不是人性化的选项。

我们可以通过控件的Invoke方法来实现跨线程调用Windows窗体控件。

下面的源代码演示线程操作:

代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace VJSDN.Tech.ThreadAccess
{
//跨线程调用的方法委托原型。
public delegate void ShowMessageMethod(string msg);

//跨线程调用的方法委托原型。
public delegate void CreateControlMethod();

//注:A线程:主线程. 主线程是指当前窗体所在的线程.
// B线程:用户创建的线程。
// C线程:带参数的线程。
public partial class Form1 : Form
{
private Thread _threadB = null; //第2个线程.创建控件。
private Thread _threadC = null; //第3个线程.带参数的线程。
private Button _btnOnB = null; //由第2个线程创建的按钮控件。
private ListBox _listBoxOnB = null;//由第2个线程创建的ListBox控件。
private Panel _PanelOnB = null;//由第2个线程创建的Panel控件。

public Form1()
{
InitializeComponent();

//是否捕获对错误线程的调用,这些调用访问控件的 System.Windows.Forms.Control.Handle 属性。
//Control.CheckForIllegalCrossThreadCalls = false;
}

private void btnCreateThreadB_Click(object sender, EventArgs e)
{
//在主线程内创建线程B.
_threadB = new Thread(new ThreadStart(MethodThreadB)); //启动线程。
_threadB.Start();
}

private void createC_Click(object sender, EventArgs e)
{
//在主线程内创建带参数的线程C.
_threadC = new Thread(new ParameterizedThreadStart(MethodThreadC));
_threadC.Start(
100); //往线程C传送参数100,计算100以内的数字加总。
}

//C线程正在运行....
private void MethodThreadC(object param)
{
int total = int.Parse(param.ToString());
this.Invoke(new ShowMessageMethod(this.ShowMessage), "线程C正在计数:1+2+n=?(n<=" + param.ToString() + ")");

int result = 0; //计数器
for (int i = 1; i <= total; i++) result += i;

this.Invoke(new ShowMessageMethod(this.ShowMessage), "线程C计算结果:" + result.ToString());
}

//B线程正在运行....
private void MethodThreadB()
{
//跨线程操作:试图在B线程内给A线程的panel2控件插入子控件.
this.Invoke(new CreateControlMethod(this.CreatePanelOnThreadB)); //创建Panel
this.Invoke(new CreateControlMethod(this.CreateButtonOnThreadB)); //创建按钮
this.Invoke(new CreateControlMethod(this.CreateListBoxOnThreadB)); //创建ListBox

this.Invoke(new ShowMessageMethod(this.ShowMessage), "线程B操作线程A内的ListBox控件");
this.Invoke(new ShowMessageMethod(this.ShowMessage), "如能显示消息,表示操作成功!");
}

//注意:这个方法与CreateControlMethod委托原型相同。
private void CreateControlCross(Label lbl)
{
_PanelOnB.Controls.Add(lbl);
}

//注意:这个方法与ShowMessageMethod委托原型相同。
private void ShowMessage(string msg)
{
this.listBox1.Items.Add(msg);
}

private void CreatePanelOnThreadB()
{
_PanelOnB
= new Panel();
_PanelOnB.BackColor
= System.Drawing.Color.Silver;
_PanelOnB.Location
= new System.Drawing.Point(264, 12);
_PanelOnB.Name
= "panel2";
_PanelOnB.Size
= new System.Drawing.Size(244, 355);
_PanelOnB.TabIndex
= 1;

this.Controls.Add(_PanelOnB); //创建Panel容器

Label _lblB
= new Label();
_lblB.AutoSize
= true;
_lblB.Font
= new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
_lblB.Location
= new System.Drawing.Point(3, 7);
_lblB.Name
= "label1";
_lblB.Size
= new System.Drawing.Size(84, 12);
_lblB.TabIndex
= 0;
_lblB.Text
= "线程B,用户创建的线程";
_PanelOnB.Controls.Add(_lblB);
//Panel容器内加入一个label
}

private void CreateButtonOnThreadB()
{
_btnOnB
= new Button();
_btnOnB.FlatStyle
= System.Windows.Forms.FlatStyle.Flat;
_btnOnB.Location
= new System.Drawing.Point(5, 63);
_btnOnB.Name
= "btnSendToA";
_btnOnB.Size
= new System.Drawing.Size(167, 23);
_btnOnB.TabIndex
= 4;
_btnOnB.Text
= "给线程A创建的控件发消息";
_btnOnB.UseVisualStyleBackColor
= true;
_btnOnB.Click
+= new System.EventHandler(this.btnSendToA_Click);

//panel2是主线程上创建的控件。
_PanelOnB.Controls.Add(_btnOnB);
}

private void CreateListBoxOnThreadB()
{
_listBoxOnB
= new ListBox();
_listBoxOnB.FormattingEnabled
= true;
_listBoxOnB.ItemHeight
= 12;
_listBoxOnB.Location
= new System.Drawing.Point(5, 240);
_listBoxOnB.Name
= "listBox2";
_listBoxOnB.Size
= new System.Drawing.Size(236, 112);
_listBoxOnB.TabIndex
= 2;

//panel2是主线程上创建的控件。
_PanelOnB.Controls.Add(_listBoxOnB);
}

private void btnSendToA_Click(object sender, EventArgs e)
{
listBox1.Items.Add(
"线程B发消息给A");
}

private void btnSendToB_Click(object sender, EventArgs e)
{
if (_listBoxOnB != null)
_listBoxOnB.Items.Add(
"线程A发消息给B");
else
MessageBox.Show(
"线程B还没创建呢!");
}

}
}

 

例程下载

 

转帖自[易学网]

posted on 2010-07-28 13:35  raychn  阅读(1291)  评论(0编辑  收藏  举报