winform程序,大量Label的Text修改,UI更新跟不上如何解决?

心云意水 2014-06-20 10:24:59
RT。大概300个Label的Text需要修改,频率是50ms一次,结果发现速度跟不上。
个人怀疑是label.Text="value"这个代码执行后,form直接刷新了一次,导致50ms内无法完成这么多的操作。

尝试过多线程更新,也尝试过单一线程用循环更新,甚至尝试过单一线程逐个更新,都无解阿。。

请问有什么办法吗??

是否有什么方法可以不让界面自动刷新,等把这300个label都修改后,手动用代码刷新?

需求无法改变,就是这么多数据需要实时监控。。。
...全文
1781 42 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
Peter石 2014-07-11
  • 打赏
  • 举报
回复
Label显示消息在少量的时候适合,我最近也在做一些上位机的东西,面对众多label串口都已经关闭了页面还在刷新。 由于我们只是要显示一句话或者一个值,而Label本身封装了很多属性在里面,而且具体是什么也不甚了解。那么简单原则,自己写一个Control来替代label即可。 我是这样解决的

public sealed partial class SuperLabel : Control
    {
        public SuperLabel()
        {
            this.DoubleBuffered = true;
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            if (this.DesignMode)
            {
                base.OnPaintBackground(e);
            }
        }

        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            Refresh();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            StringFormat format = new StringFormat {LineAlignment = StringAlignment.Center};
            e.Graphics.FillRectangle(new SolidBrush(BackColor), this.ClientRectangle);
            e.Graphics.DrawString(this.Text, this.Font,new SolidBrush(ForeColor), this.ClientRectangle, format);
        }
    }
g394594141 2014-06-23
  • 打赏
  • 举报
回复
引用 40 楼 xinyunyishui 的回复:
[quote=引用 35 楼 g394594141 的回复:] 意思用17楼代码已经可以了吗? 如果还不行,试试下面三个函数呢 this.SuspendLayout(); this.ResumeLayout(false); this.PerformLayout(); 这三个函数或许对你有帮助。 申明:我没有测试过
额。vs2010里 this.后面提示不了你说的这三个,是不是要引用什么?[/quote] 我可以点出来呢。。。你随便建一个winform,在design.cs里面都有的
Yun__ 2014-06-21
  • 打赏
  • 举报
回复
引用 34 楼 xinyunyishui 的回复:
[quote=引用 33 楼 qq6648208281 的回复:] 那么多lable为什么不能弄成关联性的 然后用一个控件自己绘制 一次刷新一批 每次刷新一次底图 然后绘制上数据就行了撒. 50ms刷新1024*800的屏幕应该可以的
每15个label为一组,是一个相同的数据源。不知道您说得自己绘制怎么做?另外,分辨率是1920*1080[/quote] 一次把一组的数据自己按坐标绘制上去. 毕竟你每次都要全部刷新这样节省了大量的绘制消息和背景的刷新
心云意水 2014-06-21
  • 打赏
  • 举报
回复
引用 35 楼 g394594141 的回复:
意思用17楼代码已经可以了吗? 如果还不行,试试下面三个函数呢 this.SuspendLayout(); this.ResumeLayout(false); this.PerformLayout(); 这三个函数或许对你有帮助。 申明:我没有测试过
额。vs2010里 this.后面提示不了你说的这三个,是不是要引用什么?
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 17 楼 xymao123 的回复:
试了一下,好像没有问题
用您的代码测试了下,的确没有问题!奇怪的是,按我的方法测试了下,300个Label更新也没问题。 后来琢磨了下,貌似问题出在UI上! 测试的代码,ui很简单,纯净的背景,什么都没有,问题是,真实程序的UI不能说花哨,但是每一个区块(总共20个区块,布局、用色相同)都有不同的背景颜色对数据进行了区分,这时候,效率就下来! 用你的代码,panel上加了张背景图上去,立刻挂了。。。。
於黾 2014-06-20
  • 打赏
  • 举报
回复
那线程用委托的方式操作UI, 委托写到循环里了么,还是委托里又使用了循环?
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 20 楼 Z65443344 的回复:
另外,你的这个多线程目测根本不需要加锁. 多线程将数据写入同一个全局数组中 然后主线程(可以是timer)就循环到数组中取数据显示就好了. 或者要加锁也应该是每个线程使用不同的锁(因为每个线程其实是对数组中的不同元素在进行更新) 不要都统一使用一个锁,会造成一个线程在写入数据的时候,其他线程无法写入对应的其他数据
昨天最后的尝试就是这样,多线程,将数据写入一个全局的数组,主线程新开一个Thread.Timer,100ms刷新一次这些数据到UI。这个Timer里第一次尝试使用了个一个for,来循环20块区域,后来修改为逐条语句写出来,实测均无改善。要想达到“流畅”的感觉,仍然需要400ms左右。
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 20 楼 Z65443344 的回复:
另外,你的这个多线程目测根本不需要加锁. 多线程将数据写入同一个全局数组中 然后主线程(可以是timer)就循环到数组中取数据显示就好了. 或者要加锁也应该是每个线程使用不同的锁(因为每个线程其实是对数组中的不同元素在进行更新) 不要都统一使用一个锁,会造成一个线程在写入数据的时候,其他线程无法写入对应的其他数据
多线程没有加锁,因为根本不会冲突,没有两个线程需要修改同一个控件的情况
於黾 2014-06-20
  • 打赏
  • 举报
回复
另外,你的这个多线程目测根本不需要加锁. 多线程将数据写入同一个全局数组中 然后主线程(可以是timer)就循环到数组中取数据显示就好了. 或者要加锁也应该是每个线程使用不同的锁(因为每个线程其实是对数组中的不同元素在进行更新) 不要都统一使用一个锁,会造成一个线程在写入数据的时候,其他线程无法写入对应的其他数据
於黾 2014-06-20
  • 打赏
  • 举报
回复
锁的时候只锁操作同一对象的部分,不要连整个通信过程都锁住了.
於黾 2014-06-20
  • 打赏
  • 举报
回复
明白了. 目测是加锁加的有问题. 导致某个线程在操作UI的时候,其他线程无法将数据更新到UI.
xymao123 2014-06-20
  • 打赏
  • 举报
回复
试了一下,好像没有问题 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { CreateLabel(); } Hashtable ht = new Hashtable(); int Seed = 0; int dis = 5; bool auto = false; int row = 10; int col = 30; void CreateLabel() { for (int i = 0; i < col; i++) { for (int j = 0; j < row; j++) { Label lb = new Label(); lb.Name = "lb" + i.ToString() + j.ToString(); lb.Width = 30; lb.Height = 15; lb.Text = "lbl"; lb.Location = new Point(lb.Width * i + dis, lb.Height * j + dis); lb.Parent = panel1; lb.Show(); ht.Add(lb.Name, lb); } } } int[,] GetValues() { int[,] vals = new int[col, row]; for (int i = 0; i < col; i++) { for (int j = 0; j < row; j++) { long tick = DateTime.Now.Ticks; Random rd = new Random(Seed); vals[i, j] = rd.Next(1, 100); Seed++; while (Seed == int.MaxValue) { Seed = 0; } } } return vals; } void Refresh() { int[,] vals = new int[col, row]; vals = GetValues(); for (int i = 0; i < col; i++) { for (int j = 0; j < row; j++) { Update("lb" + i.ToString() + j.ToString(), vals[i, j]); } } } delegate void delUpdate(string name, int val); void Update(string name, int val) { Label lb = ht[name] as Label; if (lb.InvokeRequired) { delUpdate du = new delUpdate(Update); lb.Invoke(du, new object[] { name,val}); } else { lb.Text = val.ToString(); } } void AutoRefresh() { while (auto) { Refresh(); Thread.Sleep(50); } } private void btnManaul_Click(object sender, EventArgs e) { Refresh(); } private void btnStart_Click(object sender, EventArgs e) { Thread thd = new Thread(new ThreadStart(AutoRefresh)); auto = true; thd.Start(); } private void btnEnd_Click(object sender, EventArgs e) { auto = false; } }
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 14 楼 oop_dai 的回复:
服务器控件太多必然响应,建议用html控件
。。。。HTML不是问题,问题是:HTML如何做socket通讯?
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 13 楼 Z65443344 的回复:
我想问问,所谓跟不上是什么概念 页面假死? 缓冲区中有过多的数据没有被处理导致溢出? 页面数据看起来并没有很大的波动?
仅有部分label的数据可以看到变化,绝大多数的都不动(实际上数值是有变化的),能变化的Label是随机的,不一定是哪些,有可能这几秒是某些,下几秒是另一些。但是数据通讯正常,数据并没有丢失,将数据连断开后,会发现所有的label都会被更新到最新的数据。 如果降低这个50ms的要求,目前测试出来是400ms,那么可以到所有的label都顺利的同时发生变化。
於黾 2014-06-20
  • 打赏
  • 举报
回复
我想问问,所谓跟不上是什么概念 页面假死? 缓冲区中有过多的数据没有被处理导致溢出? 页面数据看起来并没有很大的波动?
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 10 楼 Yalehorance 的回复:
可以试试多开几个线程吧,每个线程依次对主窗体线程部分控件进行刷新,同时只有1个线程启动,其他都是阻塞状态,这样应该能达到伪全部刷新的效果吧。 PS:50ms要求肯定太BT了
线程阻塞来更新,和单线程顺序更新有什么区别。。。。。话说所谓多线程,对于计算机来说,其实还是顺序执行,只是多个任务可能交叉或者乱序处理而已吧。
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 4 楼 xdashewan 的回复:
多线程为何不行,请上代码
就是一般的socket 一对多server的写法。 监听线程获取到新的连接,就新开一个线程用while(true)去获取通讯数据,然后解包,更新UI。
双木宝宝 2014-06-20
  • 打赏
  • 举报
回复
可以试试多开几个线程吧,每个线程依次对主窗体线程部分控件进行刷新,同时只有1个线程启动,其他都是阻塞状态,这样应该能达到伪全部刷新的效果吧。 PS:50ms要求肯定太BT了
心云意水 2014-06-20
  • 打赏
  • 举报
回复
说一下软件的界面情况: 一个form均分为20块区域,每块上有15个label控件。每一块区域对应一台采集器采集的数据。程序就是要把这20台采集器的数据更新到界面上。采集器和程序之间通过RJ45连接,Form做socket的server,采集器是client。 通讯、数据解包分析什么的,几乎不占时间,时间全部都耗在了更新UI上。。。
心云意水 2014-06-20
  • 打赏
  • 举报
回复
引用 6 楼 lyx_520 的回复:
用列表控件不行么?= =用300个label想当蛋疼。。如果是listview 或者 datagridview的话300条数据完全没有问题。
不可以。因为界面就是这样。。。
加载更多回复(21)

111,101

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧