C#使用线程操作控件
1.不用线程
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 100000; i++)
{
listBox1.Items.Add(i.ToString());
}
}
这种方法,界面会卡死
2.使用backgrounder背景线程
private void button1_Click(object sender, EventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.ProgressChanged += Bw_ProgressChanged;
bw.DoWork += Bw_DoWork;
bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
bw.WorkerReportsProgress = true;
bw.RunWorkerAsync();
}
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
listBox1.Items.Add("done");
}
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 1000000; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(100);
worker.ReportProgress(i );
}
}
}
private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
listBox1.Items.Add(e.ProgressPercentage.ToString());
}
3.使用Thread线程
前台线程:只有所有的前台线程都关闭才能完成程序关闭;
后台线程:只要所有的前台线程结束,后台线程自动结束;
thread = new Thread(Test);//默认情况下创建的线程是前台线程,主线程(Winform)属于前台线程;
//标记这个线程准备就绪了,可以随时被执行,具体什么时候执行这个线程,由CPU决定
thread.Start();
//如果线程执行的方法需要参数、那么要求这个参数必须是object类型
然后可以通过object类型转换为你想转换的类型。
//下面的例程 是使用线程传递参数的
private void button2_Click(object sender, EventArgs e)
{
//如果线程执行的方法需要参数、那么要求这个参数必须是object类型
Thread thread = new Thread(test2);
thread.IsBackground = true;
thread.Start("1");//传值
}
void test2(object s)
{
int num = Convert.ToInt32(s);
for (int i = 0; i < 100000; i++)
{
int sum = i + num;
textBox2.Text = sum.ToString();
}
}
private void button2_Click(object sender, EventArgs e)
{
ThreadStart threadStart = new ThreadStart(run);
Thread thread = new Thread(threadStart);
thread.IsBackground = true;
//标记这个线程准备就绪了,可以随时被执行,具体什么时候执行这个线程,由CPU决定
thread.Start();
//Thread thread = new Thread(run);
//thread.Start();
}
public void run()
{
for (int i = 1; i <= 1000000; i++)
{
listBox1.Invoke(new Action(() => {
listBox1.Items.Add(i);
}));
}
}
4.使用Task
private void button4_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
for (int i = 0; i < 1000000; i++)
{
listBox1.Invoke(new Action(() => { listBox1.Items.Add(i); }));
}
});
}
5.委托(比较规范的写法)
public delegate void SetTextHandler(string result);
Thread thread;
private void button5_Click(object sender, EventArgs e)
{
thread = new Thread(new ThreadStart(PrintEven));
thread.Start();
}
private void PrintEven()
{
for (int i = 0; i < 10000; i++)
{
setItem(i.ToString());
}
}
private void setItem(string result)
{
if (listBox1.InvokeRequired == true)
{
SetTextHandler setTextHandler = new SetTextHandler(setItem);
listBox1.Invoke(setTextHandler, new object[] { result });
}
else
{
listBox1.Items.Add(result);
}
}
6.取消跨线程检查
下面这种方法报错:程间操作无效: 从不是创建控件“listBox1”的线程访问它。”
private void button6_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(run2));
thread.Start();
}
public void run2()
{
for (int i = 0; i < 100000; i++)
{
listBox1.Items.Add(i.ToString());
}
}
解决方法:
public Form7()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;//取消跨线程检查,这种方法不推荐
}