因为C#安全机制的问题,不是本线程创建的控件,是不能直接访问的。
以下提供了两种解决办法:
一、让程序不检查跨线程调用,加入一行代码就可以了,但这样背离了C#安全机制的初衷;
二、创建委托,利用C#的Invoke 或 beginInvoke 方法从创建控件的线程来执行跨线程调用;
三、利用BackgroundWorker组件 和 DoWorkEventHandler 、 RunWorkerCompletedEventHandler委托将运算量大的逻辑运算和界面更新分开,减少UI线程负担。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace thread
{
public partial class Form1 : Form
{
Thread t;
int count = 0;
private delegate void SetTextCallback();//方法二、利用委托代理(推荐)
public Form1()
{
//方法一,加入下面这句让程序不检查跨线程调用是否合法(全局变量,慎用!!)
Control.CheckForIllegalCrossThreadCalls = false;
InitializeComponent();
t = new Thread(new ThreadStart(ThreadLb));
t.Start();
}
private void ChangeLb()
{
if (this.lb1.InvokeRequired)//判断是否跨线程调用
{
SetTextCallback d = new SetTextCallback(ChangeLb);
//this.BeginInvoke(d);//异步调用代理,程序继续往下执行
this.Invoke(d); //同步调用委托,程序在此等待
}
else
{
count++;
this.lb1.Text = count.ToString();
}
}
//使用委托的Lambda表达式
private void ChangeLb_()
{
this.Invoke(new Action(() => {
this.lb1.Text = count.ToString();
}))
}
private void ThreadLb()
{
while(true)
{
Thread.Sleep(30);
ChangeLb();
}
}
//第3种方法
private void button4_Click(object sender, EventArgs e)
{
using (BackgroundWorker bw = new BackgroundWorker())
{
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync("Tank");
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// 这里是后台线程, 用来处理复杂的逻辑
Thread.Sleep(5000);
e.Result = e.Argument + "工作线程完成";
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//这时后台线程已经完成,并返回了主线程,所以可以直接修改UI控件了
this.label4.Text = e.Result.ToString();
}
}
}