UI操作耗时太长有什么办法吗

yang1216 2015-06-04 10:09:30
我的程序用于监视几十个下位机的数据,按照要求主界面上要根据每个下位机的数据显示不同的图片,例如报警就显示红色图片。所以我做了个usercontrol,上面就是一个label一个picturebox一个tooltip,其中tooltip是用来当鼠标移动到图片上时显示几个重要的下位机数据。
然后在主界面动态加载几十个这种usercontrol,然后每秒钟根据当前数据刷新界面。现在的问题是,每更新一次界面要花2秒甚至3秒时间,系统时间显示总是每次蹦几秒,鼠标移动显示tooltip也有明显卡顿。
求助高手。


我这么写的
private void main(object sender, EventArgs e)
{
Thread thread_1s=new Thread(new ThreadStart(UI_callback));
thread_1s.IsBackground=true;
thread_1s.Start();
}
private void UI_callback()
{
while(true)
{
this.BeginInvoke(new EventHandler(RefreshUI),null);
Thread.Sleep(1000);
}
private void RefreshUI(object sender, EventArgs e)
{
toolStripStatusLabelTime.Text=DateTime.Now.Tostring();

//根据当前数据刷新界面,例如if(alarms[Station.Id].Count>0){pictureBox1.Image=imageList1.Images[3];}
}
...全文
558 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
tinghai_xu 2015-06-08
  • 打赏
  • 举报
回复
你需要的界面控件太多怎么做都会慢,解决办法是,后台多个线程得到数据后放到某个集合对象保存比如cd,前台不要嵌套那么多uc只需要一个,这个uc预先生成好多个labe picturebox toolbox这些 uc里面有一个线程去遍历cd获取数据填充到uc的控件上,如果控件有多则隐藏起来就好,动态加载比隐藏显示慢得多,如果你懂gdi自己绘制界面应对这个问题是最好的
qianxune 2015-06-05
  • 打赏
  • 举报
回复
最后!!!!!
zq1564171310 2015-06-05
  • 打赏
  • 举报
回复
Thread换BackgroundWorker试试
huaijin_li 2015-06-05
  • 打赏
  • 举报
回复
引用 2 楼 娃都会打酱油了的回复:
太复杂,你得先确认这2-3秒确定到底是花在了数据读取上,还是在控件paint上
大神
足球中国 2015-06-05
  • 打赏
  • 举报
回复
几十字不卡才怪。这个没有解决办法。你网上搜一下,出现这个问题的很多。换一种显示方式吧。
qq_28744937 2015-06-05
  • 打赏
  • 举报
回复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private void main(object sender, EventArgs e) { Thread thread_1s=new Thread(new ThreadStart(UI_callback)); thread_1s.IsBackground=true; thread_1s.Start(); } private void UI_callback() { while(true) { this.BeginInvoke(new EventHandler(RefreshUI),null); Thread.Sleep(1000); } private void RefreshUI(object sender, EventArgs e) { toolStripStatusLabelTime.Text=DateTime.Now.Tostring(); //根据当前数据刷新界面,例如if(alarms[Station.Id].Count>0){pictureBox1.Image=imageList1.Images[3];} } 加油吧 路还很长呢!~
song_scs 2015-06-05
  • 打赏
  • 举报
回复
关健的问题需要先定义一个类: class ListViewNF:System.Windows.Forms.ListView { public ListViewNF() { //开启双缓冲 this.SetStyle(ControlStyles.OptimizedDoubleBuffer|ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.EnableNotifyMessage, true); } protected override void OnNotifyMessage(Message m) { if (m.Msg != 0x14) { base.OnNotifyMessage(m); } } } 然后在Form1.Designer.cs设置UI的类型为定义的类 this.listView1 = new 命名空间.ListViewNF();
  • 打赏
  • 举报
回复
上面的回帖我没看,或许我的回复有重复,特此先说明一下。 看了一眼你的代码,它实在是太“坑爹”了啊。你的代码
Thread thread_1s=new Thread(new ThreadStart(UI_callback));
thread_1s.IsBackground=true;
thread_1s.Start();
}
private void UI_callback()
{
while(true)
{
this.BeginInvoke(new EventHandler(RefreshUI),null);
Thread.Sleep(1000);
}
这里,你弄一个线程在那里“玩儿cpu”,让它循环着(本身线程上下文相关数据结构要占用资源,它还抢占其它线程的CPU调度资源),目的是干什么呢?只是为了向主线程注册一个 RefreshUI 方法么?并且你的 RefreshUI 方法也还都是在主线程排队执行的。 .net的Timer比你自己写的线程死循环要高效得多得多。就算是你使用最低级的Timer(.net至少共有3种或者4种Timer),使用它的代码比你写的线程代码更清晰。你的这种程序根本用不着什么线程的。就像刚学编程的人一样学会拖一个Timer控件到设计画面上,就比你的代码还要好。
於黾 2015-06-05
  • 打赏
  • 举报
回复
引用 16 楼 yang1216 的回复:
[quote=引用 14 楼 yangb0803 的回复:] 既然是取数后变化, 可以用事件来通知UI变化, 而不需要用timer来刷新界面額 每个下位机数据变化, 事件通知对应UI 中的 usercontrol 变化就可以啊
因为下位机是个电表,所以可以肯定每秒钟都在变化。[/quote] 每秒都在变化,变化的应该是数字,而不是图片 图片也每秒都变化???
Forty2 2015-06-04
  • 打赏
  • 举报
回复
以下例子用了40个UserControl,每秒刷新。 建议你新建一个WinForm项目,拷贝例子代码,替换掉Form1类,即可编译运行。

public partial class Form1 : Form
{
    public Form1()
    {
        FlowLayoutPanel panel = new FlowLayoutPanel() { Padding = new Padding(8), Dock = DockStyle.Fill };
        for (int i = 0; i < 40; i++)
        {
            myUserControlList.Add(new MyUserControl());
            panel.Controls.AddRange(myUserControlList.ToArray());
        }
        this.Controls.Add(panel);
        timer.Tick += timer_Tick;
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {
        foreach (MyUserControl myControl in myUserControlList)
        {
            MyData data = new MyData() { Description = DateTime.Now.Second.ToString(), Status = random.Next(3) };
            myControl.Update(data);
        }
    }

    Random random = new Random();
    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer() { Interval = 1000 };
    List<MyUserControl> myUserControlList = new List<MyUserControl>();

    class MyData
    {
        public string Description { get; set; }
        public int Status { get; set; }
    }
    class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            this.Controls.AddRange(new Control[] { label, pictureBox });
            this.Size = new Size(60, 30);
        }

        public void Update(MyData data)
        {
            label.Text = data.Description;
            pictureBox.Image = images[data.Status % images.Length];
        }

        Label label = new Label() { Width = 30 };
        PictureBox pictureBox = new PictureBox() { Location = new Point(30, 0), };
        static Image[] images = new Image[] { SystemIcons.Warning.ToBitmap(), SystemIcons.Question.ToBitmap(), SystemIcons.Information.ToBitmap() };
    }
}
by_封爱 版主 2015-06-04
  • 打赏
  • 举报
回复
首先 你根据数据库的信息 来显示UI的 用timer本身就不对了... 应该用通知....也就是 发送改变自动触发ado本地事件而不是频发去刷....(Service Broker ,SqlDependency 你可以自行百度) 就算你玩timer至少应该这样...

           var t = new System.Timers.Timer(1000);
            t.Enabled = true;
            t.Elapsed += (o, e) =>
            {
                 ThreadPool.QueueUserWorkItem(new WaitCallback(update), null);
            };
void update(object s)
{
   this.BeginInvoke(new action(()=>{
     ///UI
   }));
}
yang1216 2015-06-04
  • 打赏
  • 举报
回复
引用 1 楼 duanzi_peng 的回复:
为什么要显示 红色 图片 ,可以用一个label 让后改变它的Background。 蹦几秒 是因为 你加了 Thread.Sleep(1000);
本来我以为更新一下界面可能就几十毫秒的事情,所以sleep(1000)算是等到下一秒,结果变成这样。
yang1216 2015-06-04
  • 打赏
  • 举报
回复
引用 5 楼 Forty2 的回复:
[quote=引用 楼主 yang1216 的回复:] ... 然后在主界面动态加载几十个这种usercontrol,然后每秒钟根据当前数据刷新界面。 ... 我这么写的 private void main(object sender, EventArgs e) { Thread thread_1s=new Thread(new ThreadStart(UI_callback)); thread_1s.IsBackground=true; thread_1s.Start(); }
是每个UserControl执行一个main(object sender, EventArgs e)吗? 如果是,有几十个UserControl就会有几十个UI_callback线程,它们将互相竞争。 建议你只在主窗口用一个定时器,定时刷新各个UserControl。 定时器用System.Windows.Forms.Timer,不需要另外BeginInvoke.[/quote] main其实是frmMain_load() 试过form.timer,更慢
yang1216 2015-06-04
  • 打赏
  • 举报
回复
引用 2 楼 starfd 的回复:
太复杂,你得先确认这2-3秒确定到底是花在了数据读取上,还是在控件paint上
数据读取和刷新UI不同的线程,所以没有干涉
Forty2 2015-06-04
  • 打赏
  • 举报
回复
引用 楼主 yang1216 的回复:
... 然后在主界面动态加载几十个这种usercontrol,然后每秒钟根据当前数据刷新界面。 ... 我这么写的 private void main(object sender, EventArgs e) { Thread thread_1s=new Thread(new ThreadStart(UI_callback)); thread_1s.IsBackground=true; thread_1s.Start(); }
是每个UserControl执行一个main(object sender, EventArgs e)吗? 如果是,有几十个UserControl就会有几十个UI_callback线程,它们将互相竞争。 建议你只在主窗口用一个定时器,定时刷新各个UserControl。 定时器用System.Windows.Forms.Timer,不需要另外BeginInvoke.
殘丿__花 2015-06-04
  • 打赏
  • 举报
回复
我也是觉得应该是Thread.Sleep(1000);问题 即使是几十个控件,你可以每次只对一个控件刷新而不是整个窗体
那城 2015-06-04
  • 打赏
  • 举报
回复
用异步的方式就可以解决了
  • 打赏
  • 举报
回复
太复杂,你得先确认这2-3秒确定到底是花在了数据读取上,还是在控件paint上
exception92 2015-06-04
  • 打赏
  • 举报
回复
为什么要显示 红色 图片 ,可以用一个label 让后改变它的Background。 蹦几秒 是因为 你加了 Thread.Sleep(1000);
effun 2015-06-04
  • 打赏
  • 举报
回复
引用 15 楼 yang1216 的回复:
[quote=引用 12 楼 effun 的回复:] 从你提供的代码里看不出什么问题,我猜问题应该在RefreshUI方法的后续代码里。 我觉得你得先确认耗时的操作出现在哪个部分,是从下位机取数还是更新UI,再来对症下药。
我用stopwatch看过,耗时最多的在RefreshUI方法也就是换图片和改tooltip那里。 我的办法有点蠢,每次每个下位机都重新设置image和tooltip。不过我觉得这是对的,因为数据随时都在变,再去判断是不是和上次一样也没啥意思。[/quote] 更新几十个控件的内容应该不会造成界面卡顿几秒这么多,我想问题可能还是出现在下位机取数这里,你试试不要去下位机取数,直接搞一点模拟数据,这样卡顿的情况会不会好点。
加载更多回复(5)

110,566

社区成员

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

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

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