• WinForm跨线程访问问题


    序言

    方案一:去掉线程访问主线程UI控件的安全检查(不推荐)

    Control.CheckForIllegalCrossThreadCalls = false;

    方案二:使用委托,将对主线程的UI控件操作推送了该线程的消息队列里,使用的方法为:Invoke方法和BeginInvoke方法,前一个是同步方法,后一个为异步方法;

    使用async 关键字可避免主线程等待

    this.BeginInvoke(new Action(async () =>
                  {
                      label1.Text = $"Count:{Count},Time: {DateTime.Now.ToString()} ";
                      await Task.Delay(5000);
                      label1.Text = $"Finished {DateTime.Now.ToString()} ";
                  }));

    方案三:使用同步上下文:SynchronizationContext方法,该方法是取得主线程的上下文信息,然后在子线程将访问UI控件方法推送到UI上下文的消息队列里,使用POST或者Send;

    方案四:在命名空间:   System.ComponentModel 里有个BackgroundWorker类,它是在一个单独的线程里执行

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它。

     子线程更新主线程方法

    Control的Invoke和BeginInvoke

    Application.DoEvents();

    Application.DoEvents可以防止界面停止响应

     private void button1_Click(object sender, EventArgs e)
            {
                for (int i = 0; i < 10000; i++)
                {
                    label1.Text = i.ToString();
                    Application.DoEvents();
                }
            }

    测试了一下,没有Application.DoEvents()的时候,Label基本处于假死机状态,最后显示一个9999,加上后会数字变换正常显示。

    如果没有加上DoEvents的话,由于循环时间会比较久就会出现假死的状态,而且程序不能处理其他的事件。而如果加上DoEvents的话就会对文本框的值实时响应,给用户带来较好的用户体验,可是DoEvents也带来了效率上的问题,处理同样的一个事件调用了DoEvents后效率降低了好几倍,这也是为什么要慎用的原因了。

    理解C#中的ExecutionContext vs SynchronizationContext

    为什么需要SynchronizationContext

    众所周知,.NET Framework 支持几种不同类型的应用程序,而每种应用程序所支持的线程模型也不相同。

    Console、Windows Service应用程序不对线程做任何限制,即在这两种应用程序中,线程可做任何它想做的事;

    而Windows Forms(从.NET Framework 2.0开始)、WPF、Silverlight支持的线程模型是:窗体控件只允许创建它的线程可以对其进行更新。

    如果是非创建线程对其更新,在VS中调试时,则会抛出InvalidOperationException异常,并提示:从不是创建控件的线程访问它。

    虽然在非调试状态下不会抛出这个异常,但这样做不是线程安全的。

    在Windows Forms中,为了解决从非创建线程更新的问题,我们可以通过调用Form.CheckForIllegalCrossThreadCalls属性并将其值设为false,

    正如前面所说,这不是线程安全的,所以不建议这样做。于是MS为我们提供了一种新的更新方式:通过委托转到创建线程进行更新。

    什么是SynchronizationContext

    SynchronizationContext在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯。

    需要注意的是,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的。故获取SynchronizationContext也只能在UI线程上进行SynchronizationContext context = SynchronizationContext.Current;

    资料

    SynchronizationContext对Windows Forms窗体控件的更新方法

    SynchronizationContext线程间同步

    线程之间的通讯---SynchronizationContext

    https://www.cnblogs.com/kiminozo/archive/2012/02/06/2340609.html

    https://www.cnblogs.com/xiaoxiaotank/p/13666913.html

    https://www.cnblogs.com/mqxs/p/4288644.html

  • 相关阅读:
    centos6 安装 directAdmin
    rpm源码安装mysql
    linux添加自启服务(程序)
    linux配置ip的方法
    开发规范
    Video Processing and Communications:(视频处理和通信)
    低清图像变成高清图像 原理
    CentOS和Ubuntu哪个好?
    遥感图像处理与一般的图像处理的区别
    GAE、SAE与BAE的对比分析(百度云)
  • 原文地址:https://www.cnblogs.com/cnki/p/15516997.html
Copyright © 2020-2023  润新知