Winform跨线程访问UI以及UI卡死解决方案
本文主要根据自己遇到的开发问题做了一个测试案例,总结了一下Winform开发中遇到的界面卡死和跨线程访问UI的一些问题,主要是Invoke和BeginInvoke的使用选择。
private void button2_Click(object sender, EventArgs e) { for (int i = 0; i < 100; i++)//界面不会卡死,但会卡顿 { new Thread( (temp1) => { //richTextBox1.Text = "1000";//不可访问UI Thread.Sleep(Convert.ToInt32(temp1)); } ).Start("1000"); } //========================================================= for (int i = 0; i < 100; i++)//界面会卡死 { new Thread( (temp1) => { MyDelegate mydel = (temp2) => { richTextBox1.Text = "1000";//可访问UI Thread.Sleep(Convert.ToInt32(temp1)); }; BeginInvoke(mydel, temp1); } ).Start("1000"); } for (int i = 0; i < 100; i++)//界面会卡死 { new Thread( (temp1) => { MyDelegate mydel = (temp2) => { richTextBox1.Text = "1000";//可访问UI Thread.Sleep(Convert.ToInt32(temp1)); }; Invoke(mydel, temp1); } ).Start("1000"); } //========================================================= for (int i = 0; i < 100; i++)//界面不会卡死,不会卡顿 { new Thread( (temp1) => { MyDelegate mydel = (temp2) => { //richTextBox1.Text = "1000";//不可访问UI Thread.Sleep(Convert.ToInt32(temp2)); }; mydel.BeginInvoke((string)temp1, null, null); } ).Start("1000"); } for (int i = 0; i < 100; i++)//界面不会卡死,但会卡顿 { new Thread( (temp1) => { MyDelegate mydel = (temp2) => { //richTextBox1.Text = "1000";//不可访问UI Thread.Sleep(Convert.ToInt32(temp2)); }; mydel.Invoke((string)temp1); } ).Start("1000"); } //========================================================= for (int i = 0; i < 100; i++)//界面卡死 { MyDelegate myde2 = (temp1) => { richTextBox1.Text = "1000";//可访问UI Thread.Sleep(Convert.ToInt32(temp1)); }; BeginInvoke(myde2, "1000"); } for (int i = 0; i < 100; i++)//界面卡死 { MyDelegate myde2 = (temp1) => { richTextBox1.Text = "1000";//可访问UI Thread.Sleep(Convert.ToInt32(temp1)); }; Invoke(myde2, "1000"); } for (int i = 0; i < 100; i++)//界面不卡死 { MyDelegate myde3 = (temp1) => { richTextBox1.Text = temp1;//无法访问UI Thread.Sleep(Convert.ToInt32(temp1)); }; myde3.BeginInvoke("1000", null, null); } for (int i = 0; i < 100; i++)//界面卡死 { MyDelegate myde3 = (temp1) => { richTextBox1.Text = temp1;//可以访问UI Thread.Sleep(Convert.ToInt32(temp1)); }; myde3.Invoke("1000"); } //结论:①Invoke(mydel,params[]) 在主线程上立即执行委托函数 // ②BeginInvoke(mydel,params[]) 在主线程上异步执行委托函数 // ③mydel.Invoke(params[]) 在委托所在线程上立即执行委托函数 // ④mydel.BeginInvoke(params[],callback,object) 在委托所在线程上异步执行委托函数 //跨线程访问UI使用①或②,但是可能存在UI阻塞问题 //防止UI阻塞有两种情况可选:1、当委托所在线程为主线程时,只能使用③ // 2、当委托所在线程为非主线程时,③和④都可以使用 }