c#中多线程访问winform控件的若干问题

我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题
看例子

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(new ThreadStart(ThreadFunction));
            thread.IsBackground = true;
            thread.Start();
           
        }
        private void ThreadFunction()
        {
            while(true)
            {
                textBox1.Text = DateTime.Now.ToString();
                Thread.Sleep(1000);
            }
        }
    }

运行后会看到系统抛出异常
在这里插入图片描述
这是因为.net 2.0以后加强了安全机制,不允许在winform中直接跨线程访问控件的属性
解决方案
第一种
Control.CheckForIllegalCrossThreadCalls = false; 加入这句代码以后发现程序可以正常运行了
然而,这种方法不可取。我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。而且像这种跨线程访问是否存在异常,我们通常都会去检查。如果项目中其他人修改了这个属性,那么我们的方案就失败了,我们要采取另外的方案。

public partial class Form1 : Form
    {
        private delegate void FlushClient();
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(CrossThreadFlush);
            thread.IsBackground = true;
            thread.Start();

        }
        private void CrossThreadFlush()
        {
            FlushClient flush = ThreadFunction;
            this.BeginInvoke(flush);
        }

            private void ThreadFunction()
        {
            while (true)
            {
                textBox1.Text = DateTime.Now.ToString();
                Thread.Sleep(1000);
            }
        }
    }

使用这种方式我们可以看到跨线程访问的异常没有了。但是新问题出现了,界面没有响应了
我们只是让新开的线程无限循环刷新,理论上应该不会对主线程产生影响的。其实不然,这种方式其实相当于把这个新开的线程“注入”到了主控制线程中,它取得了主线程的控制。只要这个线程不返回,那么主线程将永远都无法响应。
这说明 BeginInvoke 所调用的委托根本就是在 UI 线程中执行的。
C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它

猜你喜欢

转载自blog.csdn.net/weixin_44007644/article/details/86706110