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、当委托所在线程为非主线程时,③和④都可以使用
        }