• winform自定义控件跨线程更新UI的疑问


    //定义一个自定义控件,包含如下属性和方法,绑定此working属性到worker的working属性
    bool _working = false; string _thread_name1 = ""; string _thread_name2 = ""; public bool working { get { return _working; } set { if (value != _working) { _working = value; //在这里把触发属性更改的线程名称记录下来 _thread_name1 = string.IsNullOrEmpty(System.Threading.Thread.CurrentThread.Name)?"null": System.Threading.Thread.CurrentThread.Name; //Invalidate(); Refresh(); } } } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); //根据属性working的值绘背景颜色,用来监控属性确实被更改了 if (working) { e.Graphics.FillRectangle(Brushes.Green, ClientRectangle); } else { e.Graphics.FillRectangle(Brushes.Red, ClientRectangle); } //打印触发属性更改的线程名称 e.Graphics.DrawString(_thread_name1, Font, Brushes.Black,0,0); //打印当前(执行重绘方法)线程名称 _thread_name2 = string.IsNullOrEmpty(System.Threading.Thread.CurrentThread.Name) ? "null" : System.Threading.Thread.CurrentThread.Name; e.Graphics.DrawString(_thread_name2, Font, Brushes.Blue, 0, Height/2); }
    //再定义一个worker类,在start()/stop()方法里更改属性working
    public class worker : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; bool _working = false; public bool working { get { return _working; } set { if (value != _working) { _working = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("working")); } } } } Thread _work_thread; bool _release_work = false; public void start_work() { if (_work_thread == null || _work_thread.ThreadState != ThreadState.Running) { _release_work = true; _work_thread = new Thread(work); _work_thread.IsBackground = true; _work_thread.Start(); } _work_thread = new Thread(work); _work_thread.IsBackground = true; _work_thread.Name = "working thread"; //Thread.CurrentThread.Name = "main thread"; _work_thread.Start(); } public void stop_work() { _release_work = false; _working = false; } public void work() { while(_release_work) { working = true; Thread.Sleep(200); if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("workdone")); } working = false; } }

    这个时候就发现,触发自定义控件属性更改的实践线程是不固定的,有时候是主线程,有时候是辅线程,自定义控件在重绘的时候从来不报跨线程错误!而同样绑定working属性的其他winfrom控件立刻报错。这是为什么呢?折腾了好久找到后面的答案。实验的一下确实如此,onpaint的线程一定是主线程。如果换成refresh()方法重绘控件,照样立刻报跨线程错误。

    MSDN:
    调用 Invalidate 方法并不强制同步绘制;若要强制同步绘制,请在调用 Invalidate 方法之后调用 Update 方法。在不带参数的情况下调用此方法时,会将整个工作区添加到更新区域。

    这句话的意思是如果我在自定义的方法中调用了Invalidate,那么相当于我告诉程序,当前的页面无效,你必须给我重新绘制,但是不是立即重新绘制,而是放置一个WM_PAINT消息到消息队列中,操作系统收到这个消息后才能绘制窗体。

    不管怎样,系统肯定会重新绘制调用Invalidate的窗体或者控件对象。
    ---------------------
    作者:阿达King哥
    来源:CSDN
    原文:https://blog.csdn.net/JimFire/article/details/41206413
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    js 闭包范式概述
    [置顶] 学习JDK源码:编程习惯和设计模式
    第七届蓝桥杯JavaB组国(决)赛部分真题
    第七届蓝桥杯JavaA组国(决)赛部分真题
    第七届蓝桥杯JavaA组国(决)赛部分真题
    第七届蓝桥杯JavaA组国(决)赛部分真题
    第七届蓝桥杯JavaA组国(决)赛部分真题
    第七届蓝桥杯JavaA组国(决)赛部分真题
    Java实现蓝桥杯历届真题国王的遗产
    Java实现蓝桥杯历届真题国王的遗产
  • 原文地址:https://www.cnblogs.com/franklin2018/p/10700739.html
Copyright © 2020-2023  润新知