.NET编程之子线程和UI交互,WPF、WinForm、MFC对比

8 篇文章 1 订阅

一、引言

我们知道不管什么语言,什么框架WinForm,WPF,MFC也好,子线程都不能直接去更新UI中的控件。1是为了保证UI的流畅,2是UI线程是没有对象锁的,如果有其他线程同时去操作的话,容易造成不可预期的结果。
MFC中我们一般都是发送自定义消息SendMessage或者PostMessage去通知UI需要更新某些控件元素了,发送的消息会到UI线程自己的消息队列里,UI线程通过消息循环,循环到自定义消息后会更新特定的UI元素。MFC中这种实现原理比较接近WINAPI,如果完全理解了,那不管其他什么语言都非常容易理解,一通百通。

二、.NET用法示例

1.winform方法一:Invoke方法

//子线程
private void WorkThread1()
        {
            while (true)
            {
                UpdateLabel1(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                Thread.Sleep(500);
            }
        }

 private void UpdateLabel1(string msg)
        {
        //如果调用控件的线程和创建创建控件的线程不是同一个则为True
            if (this.label1.InvokeRequired)
            {
                this.label1.Invoke(new Action<string>(UpdateLabel1), new object[] { msg });
            }
            else
            {
                this.label1.Text = msg;
            }
        }

这种方法不是很简洁,比较啰嗦

2.winform方法二:BeginInvoke方法

private void WorkThread()
        {
            while (true)
            {
                this.label1.BeginInvoke((MethodInvoker)delegate
                {
                    label1.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                });
                Thread.Sleep(500);
            }
        }

3.wpf方法一:Invoke方法

//启动子线程
 private void Button_Click(object sender, RoutedEventArgs e)
        {
            Thread thread = new Thread(ModifyUI);
            thread.Start();
        }
        
//更新UI线程创建的对象
        private void ModifyUI()
        {
            // 模拟一些工作正在进行
            Thread.Sleep(TimeSpan.FromSeconds(2));
            this.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
            {
                label1.Content = "欢迎你光临WPF的世界,Dispatcher";
            });
        }

4.wpf方法二:BeginInvoke方法,基本同Invoke方法

 private void ModifyUI()
        {
            // 模拟一些工作正在进行
            Thread.Sleep(TimeSpan.FromSeconds(2));
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate ()
            {
                label1.Content = "欢迎你光临WPF的世界,Dispatcher";
            });
        }

DispatcherPriority定义了很多优先级:
在这里插入图片描述
5.wpf方法三:使用BackgroupWorker组建

这个组建在winform,wpf中都有,专门为简化子线程和UI交互而设计的,比如实现了进度通知,支持取消,完成通知等。
用法很简单,如下:

//创建BackgroundWorker实例

BackgroundWorker backgroundWorker;
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;

//可以返回工作进度
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;

//支持取消
backgroundWorker.WorkerSupportsCancellation = true;

//开始执行DoWork
backgroundWorker.RunWorkerAsync();

三、最后

在wpf中DispatcherObject对象只能被创建它的线程所访问,其他线程修改 DispatcherObject需要取得对应的Dispatcher,调用Invoke或者BeginInvoke来投入任务。Dispatcher的一些设计思路包括 Invoke和BeginInvoke等从WinForm时代就是一直存在的,只是使用了Dispatcher来封装这些线程级的操作。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏克贝塔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值