• 窗体与子线程的交互


    窗体与子线程间通讯方法

    窗体上的UI默认情况下不允许使用子线程(或者其它非创建控件的UI线程)去控制(这在NET2.0以下是允许的,但是考虑到安全性等问题,从2.0开始就禁止使用这个功能,除非Form的CheckForIllegalCrossThreadCalls=true,不推荐这样使用)。

    那么怎么办呢?

    1)使用Invoke或者BeginInvoke方法:

    用一个线程,里边调用Invoke或者BeginInvoke方法即可:

    public partial class Form1 : Form
    {
    public void Processing(int num)
    {
    int answer = 2;
    Task t = new Task(() =>
    {
    for (int i = 3; i <= num; i++)
    {
    answer *= i;
    }
    this.BeginInvoke(new MethodInvoker(() => { Thread.Sleep(3000); MessageBox.Show("Finished!") }));
    MessageBox.Show("OK");
    });
    t.Start();
    }
    public Form1()
    {
    InitializeComponent();

    }
    private void button1_Click(object sender, EventArgs e)
    {
    MessageBox.Show("First!");
    Processing(10);
    }
    }

    这里值得注意的:
    1)BeginInvoke:这里的“异步”并不是针对UI线程,而是说当Control的BeginInvoke在某个子线程中调用时,子线程中BeginInvoke后面的代码(弹出“Finished”框框)会先执行,然后等到BeginInvoke中的那个委托方法完全执行完毕之后Label才会被赋值。如果改成Invoke,那么“OK”永远在Invoke的委托代码彻底执行完毕之后才被执行。
    所以BeginInvoke=Invoke(在UI主线程中,所以不建议在主线程中直接这样调用)

    2)线程同步SynchronizedContext:
    public partial class Form1 : Form
    {
    public void Processing(int num,SynchronizationContext context)
    {
    int answer = 2;
    Task t = new Task(() =>
    {
    for (int i = 3; i <= num; i++)
    {
    answer *= i;
    }
    SynchronizationContext.SetSynchronizationContext(context);
    SynchronizationContext.Current.Post((obj) => { Thread.Sleep(3000); MessageBox.Show("Finished"); }, null);
    MessageBox.Show("Last");
    });
    t.Start();
    }
    public Form1()
    {
    InitializeComponent();

    }
    private void button1_Click(object sender, EventArgs e)
    {
    MessageBox.Show("First!");
    Processing(10,SynchronizationContext.Current);
    }
    }

    和BeginInvoke、Invoke类似,注意:
    1)SynchronizationContext:唯独在UI窗体线程中会自动初始化(button1_Click事件中SynchronizationContext.Current为当前窗体),其它线程与线程要交互,必须通过new SynchronizationContext()实现)。
    2)Post方法等同于BeginInvoke作用,Send等同于Invoke作用。

    大家如果仔细实验代码,还会发现无论何种情况,弹出“Finished”框框总是界面“假死”3秒,是的,证明了以上4个方法都是在UI线程上执行的(只不过是同步或者异步向窗体消息泵发送信息而已)。所以应该“一次性地把数据在子线程中先全部处理干净(在Invoke,BeginInvoke,Send或者Post前得出结果,写代码),然后一次性发送通知给窗体,更新界面即可)。

    另外注意:

    任何委托(Delegate)也有BeginInvoke方法,它是真正的异步,一旦Invoke一定是开辟一个线程去执行的。

  • 相关阅读:
    C#打造51CTO自动签到服务领取无忧币之开篇
    Windows8开发实战之文本布局
    设计模式之抽像工厂
    PDM只显示表名称不显示列表名称
    JS 判断中英文字符长度
    C#操作剪贴板实现复制粘贴
    Chrome控制台设置浏览器Cookie
    通过Mysql查询分析器 建库建表语句
    推荐两个VS开发工具插件
    C#经典机试题(猫叫)
  • 原文地址:https://www.cnblogs.com/ServiceboyNew/p/3880636.html
Copyright © 2020-2023  润新知