博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
winform线程间操作UI的五种方法
阅读量:6740 次
发布时间:2019-06-25

本文共 7310 字,大约阅读时间需要 24 分钟。

转自:http://www.cnblogs.com/huhu583/p/5520291.html

经常因为需要在线程间操作UI而头疼,总结了一下,记录出来,以后方便查阅。

方法一

通过设置窗体属性,取消线程间的安全检查。(最简单,最省事,也是最不负责任的一种)

 

1 public partial class one : Form 2     { 3         public one() 4         { 5             InitializeComponent(); 6             Control.CheckForIllegalCrossThreadCalls = false;//取消线程间的安全检查 7         } 8  9         private void Form1_Load(object sender, EventArgs e)10         {11             Thread listen = new Thread(new ThreadStart(receive));12             listen.IsBackground = true;13             listen.Start();14         }15         private void receive()16         {17             UdpClient uc = new UdpClient(5839);18             while (true)19             {20                 IPEndPoint ip = null;21                 byte[] message = uc.Receive(ref ip);22                 string messagestring = Encoding.UTF8.GetString(message);23                 textBox1.Text = messagestring;24             }25         }26 27         private void button1_Click(object sender, EventArgs e)28         {29             UdpClient uc = new UdpClient("192.168.0.53",5839);30             string messagestring = "改变啦!";31             byte[] message = Encoding.UTF8.GetBytes(messagestring);32             uc.Send(message,message.Length);33             uc.Close();34         }35     }

上述代码,就是在一个窗体内,本窗体给本窗体通过udp发送消息。接收线程接到发来的消息后,使窗体的UI发生改变。效果图如下:

这种方法,可能会导致不安全,不推荐使用。

 

方法二

通过设置全局变量属性,利用timer模拟实现此效果。

1 public partial class two : Form 2     { 3         string messagestring = ""; 4         public two() 5         { 6             InitializeComponent(); 7         } 8  9         private void two_Load(object sender, EventArgs e)10         {11             Thread listen = new Thread(new ThreadStart(receive));12             listen.IsBackground = true;13             listen.Start();14             timer1.Start();15         }16         private void receive()17         {18             UdpClient uc = new UdpClient(5839);19             while(true)20             {21                 IPEndPoint ip = null;22                 byte[] message = uc.Receive(ref ip);23                 messagestring = Encoding.UTF8.GetString(message);24             }25         }26 27         private void button1_Click(object sender, EventArgs e)28         {29             UdpClient uc = new UdpClient("127.0.0.1",5839);30             string message = "改变啦!";31             byte[] send = Encoding.UTF8.GetBytes(message);32             uc.Send(send,send.Length);33             uc.Close();34         }35 36         private void timer1_Tick(object sender, EventArgs e)37         {38             textBox1.Text = messagestring;39         }40     }

此方法的原理是,当接收线程接收到发来的消息后,将消息赋值到一个全局变量上,同时timer一直在运行textbox1.text = messagestring;

UI的改变交给timer来实现。效果图如下。

这种方法,不推荐使用,占用资源过多,并且根据timer时间设置的不同会有不同的延时。

方法三

通过winform自带的backgroundworker取代thread进行异步操作。

 

1 public partial class three : Form 2     { 3         public three() 4         { 5             InitializeComponent(); 6         } 7  8         private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 9         {10             UdpClient uc = new UdpClient("127.0.0.1",5839);11             string messagestring = "改变啦!";12             byte[] message = Encoding.UTF8.GetBytes(messagestring);13             uc.Send(message,message.Length);14             uc.Close();15         }16         private void button1_Click(object sender, EventArgs e)17         {18             backgroundWorker1.RunWorkerAsync();19         }20 21         private void three_Load(object sender, EventArgs e)22         {23             backgroundWorker2.RunWorkerAsync();24         }25 26         private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)27         {28             UdpClient uc = new UdpClient(5839);29             while(true)30             {31                 IPEndPoint ip = null;32                 byte[] message = uc.Receive(ref ip);33                 string messagestring = Encoding.UTF8.GetString(message);34                 backgroundWorker2.ReportProgress(50, messagestring);35             }36         }37 38         private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)39         {40             textBox1.Text = e.UserState.ToString();41         }42 43     }

这种方法,不推荐使用,虽然并没有什么不好的。但是就是感觉特别挫,因为只局限于winform,到了其它的地方,还不是得用thread来实现,使用这种方法解决问题,治标不治本。

方法四

通过UI线程的SynchronizationContext的Post/Send方法更新,代码如下

1 public partial class fourth : Form 2     { 3         SynchronizationContext SyncContext = null; 4         public fourth() 5         { 6             InitializeComponent(); 7             SyncContext = SynchronizationContext.Current; 8         } 9 10         private void fourth_Load(object sender, EventArgs e)11         {12             Thread listen = new Thread(new ThreadStart(receive));13             listen.IsBackground = true;14             listen.Start();15         }16         private void receive()17         {18             UdpClient uc = new UdpClient(5839);19             while (true)20             {21                 IPEndPoint ip = null;22                 byte[] message = uc.Receive(ref ip);23                 string messagestring = Encoding.UTF8.GetString(message);24                 SyncContext.Post(change,messagestring);25             }26         }27         private void change(object str)28         {29             textBox1.Text = str.ToString();30         }31         private void button1_Click(object sender, EventArgs e)32         {33             UdpClient uc = new UdpClient("127.0.0.1", 5839);34             byte[] message = Encoding.UTF8.GetBytes("改变啦!");35             uc.Send(message, message.Length);36             uc.Close();37         }38     }

原理是,在线程执行过程中,需要更新到UI控件上的数据不再直接更新,而是通过UI线程上下文的Post/Send方法,将数据以异步/同步消息的形式发送到UI线程的消息队列;UI线程收到该消息后,根据消息是异步消息还是同步消息来决定通过异步/同步的方式调用SetTextSafePost方法直接更新自己的控件了。

在本质上,向UI线程发送的消息并不是简单数据,而是一条委托调用命令。效果图如下

这种方法,推荐使用,是不错的解决问题的好方法。

方法五

通过设置UI控件的Invoke和BeginInvoke方法实现更新,代码如下

1 public partial class fifth : Form 2     { 3         delegate void Change(string text); 4         public fifth() 5         { 6             InitializeComponent(); 7         } 8         private void Settext(string text) 9         {10             textBox1.Text = text;11         }12 13         private void fifth_Load(object sender, EventArgs e)14         {15             Thread listen = new Thread(new ThreadStart(receive));16             listen.IsBackground = true;17             listen.Start();18         }19         private void receive()20         {21             UdpClient uc = new UdpClient(5839);22             while (true)23             {24                 IPEndPoint ip = null;25                 byte[] message = uc.Receive(ref ip);26                 string messagestring = Encoding.UTF8.GetString(message);27                 this.BeginInvoke(new Change(Settext),messagestring);28             }29         }30 31         private void button1_Click(object sender, EventArgs e)32         {33             UdpClient uc = new UdpClient("127.0.0.1", 5839);34             byte[] message = Encoding.UTF8.GetBytes("改变啦!");35             uc.Send(message,message.Length);36             uc.Close();37         }38     }

 

这个方法是目前跨线程更新UI使用的主流方法,使用控件的Invoke/BegainInvoke方法,将委托转到UI线程上调用,实现线程安全的更新。效果图如下

这种方法推荐使用,是当前的主流。

总结,多线程间会经常使用到委托,对委托的理解十分关键。

 

转载于:https://www.cnblogs.com/bjxingch/articles/6831387.html

你可能感兴趣的文章
spring初始化bean的顺序
查看>>
Office Online 体验
查看>>
vim常用操作
查看>>
Putty使用密钥自动登陆SSH
查看>>
Nginx 502gateway错误故障解决
查看>>
关于ajax接受json格式的数据
查看>>
基于AIRMA模型对订单总额未来七天的预测
查看>>
GNS3中PIX防火墙、ASA防火墙、juniper路由器、IDS、Qemu客户机模拟环境搭建
查看>>
habse java api使用操作
查看>>
Linux初学之文件查找
查看>>
Weka开发[3]-Evaluation类
查看>>
使用PHP开发你必须得注意的要点
查看>>
RunTime.getRunTime().addShutdownHook用法
查看>>
我的友情链接
查看>>
.NET简谈特性(代码属性)
查看>>
《转》OpenStack添加监控服务
查看>>
《转》qt中添加背景图片(stylesheet)
查看>>
温故知新——JS中创建对象或类的方法
查看>>
centos 正确安装vitualbox
查看>>
带有机器人框架的.NET自动化测试
查看>>