如何解决 C#WinForm项目中使用控件较多时卡顿问题

csdn_xhzq 2020-01-21 01:21:17
如何解决 C#WinForm项目中使用控件较多时出现刷新问题,具体如下 图:
...全文
12101 21 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
msmvc 2022-04-13
  • 打赏
  • 举报
回复

使用MDI窗体, 控制打开N个form. form并排排列, 每个form中放少量控件

dotent· 2020-12-12
  • 打赏
  • 举报
回复
有没有界面小化后再还原界面出现显示不全问题,过会就可以显示这样的问题,如果式这样的问题可以,首先布局好,再放入这些控件,加载就会直接出来,
思无心 2020-12-01
  • 打赏
  • 举报
回复 1
引用 12 楼 zhi_weiyang 的回复:
protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } } 这个代码放到你要打开的窗体的代码片里(类中),直接用,这个作用是进行双缓存处理。
这个加上后,最小化后再打开Form显示异常
良朋 2020-11-23
  • 打赏
  • 举报
回复
控件多了,FORM刷新时(第一次显示也是一次刷新),它貌似有显示延迟现象,你可以说它是卡顿,这其实和线程无关,因为没数据需要在线程中处理。和显卡和显存的关系大一些,如果显卡显存大、GPU处理速度快,那显示刷新也快。
datafansbj 2020-11-23
  • 打赏
  • 举报
回复
将数据获取、处理当然不宜放在 UI 线程,这个大家应该有共识,不需再行讨论。界面卡顿还有另外一个原因,就是 ,Net 的窗体绘图机制, GDI 或 GDI+ 都不是高效的方式。界面东西多的时候,即使没有任何数据也会卡顿,所以使用 .Net 开发桌面程序,界面不宜太花俏、复杂。以前曾接触过一个项目,使用 Net 开发(无数据库,就是处理大量数据实时显示),界面复杂控件多,卡顿的不行,双缓冲也没什么效果。只好精简界面,尽量不用带句柄的控件,某些组件自己写代码重绘等,结果才勉强能接受。
  • 打赏
  • 举报
回复
改业务,别用太多的控件
派大奇 2020-11-21
  • 打赏
  • 举报
回复
不错不错 有不错的答案
八爻老骥 2020-11-21
  • 打赏
  • 举报
回复
Winform就是这样的,控件多了就会卡顿闪烁,这是GDI画图的通病,开双缓存也是治标不治本。要么将窗体进行拆分,控件数量控制以30个以内,要么换成其它技术平台,比如WPF、H5、MFC等。
zhi_weiyang 2020-11-20
  • 打赏
  • 举报
回复
protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x02000000; return cp; } } 这个代码放到你要打开的窗体的代码片里(类中),直接用,这个作用是进行双缓存处理。
6lilu9 2020-01-23
  • 打赏
  • 举报
回复
引用 3 楼 以专业开发人员为伍 的回复:
与 UI 无关的处理应该单独、异步执行,然后当执行完毕之后才调用主线程来更新界面。例如测试下面的例子:
using System;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void button1_Click(object sender, EventArgs e)
        {
            button1.Text = "测试开始";
            Test();
        }

        void Test()
        {
            Thread.Sleep(10000);
            this.button1.Text = "测试完成";
        }
    }
}
当你点击按钮的时候,你会发现10秒钟之内界面卡死了,窗口根本用鼠标拖动不了!这就是很糟糕的程序。而改成
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        async void button1_Click(object sender, EventArgs e)
        {
            button1.Text = "测试开始";
            await Test();
            this.button1.Text = "测试完成";
        }

        Task Test()
        {
            return Task.Run(() =>   //把与UI刷新无关的语句放到这个匿名委托中执行
            {
                Thread.Sleep(10000);
            });
        }
    }
}
你会发现在耗时过程执行过程中也能自由地拖动窗口。 假设在异步并发过程中要修改窗口控件,那么需要使用委托来访问控件。例如:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        async void button1_Click(object sender, EventArgs e)
        {
            button1.Text = "测试开始";
            await Test();
            this.button1.Text = "测试完成";
        }

        Task Test()
        {
            return Task.Run(() =>   //把与UI刷新无关的语句放到这个匿名委托中执行
            {
                Thread.Sleep(2500);
                this.button1.BeginInvoke((Action)delegate
                {
                    this.button1.Text = "1";
                });
                Thread.Sleep(2500);
                this.button1.BeginInvoke((Action)delegate
                {
                    this.button1.Text = "2";
                });
                Thread.Sleep(2500);
                this.button1.BeginInvoke((Action)delegate
                {
                    this.button1.Text = "3";
                });
                Thread.Sleep(2500);
            });
        }
    }
}
这里,在耗时的异步过程执行过程中访问了 UI 界面控件,就需要使用 BeginInvoke 委托来操作控件,使用 BeginInvoke.Invoke 委托来操作控件,这是15年前就在 .net 中有的操作规范。
满分!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  • 打赏
  • 举报
回复
简单总结一下,就是,其实你绝大部分时间是用与界面 UI 无关的操作把人家 UI 线程给“卡死了、阻塞了”,造成界面看起来死了一样。其实界面可以很灵敏,可以随时刷新、可以迅速响应各种事件。不是程序形能不好,都是设计者的知识、是人为惹的祸。
  • 打赏
  • 举报
回复 1
与 UI 无关的处理应该单独、异步执行,然后当执行完毕之后才调用主线程来更新界面。例如测试下面的例子:
using System;
using System.Threading;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

void button1_Click(object sender, EventArgs e)
{
button1.Text = "测试开始";
Test();
}

void Test()
{
Thread.Sleep(10000);
this.button1.Text = "测试完成";
}
}
}

当你点击按钮的时候,你会发现10秒钟之内界面卡死了,窗口根本用鼠标拖动不了!这就是很糟糕的程序。而改成
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

async void button1_Click(object sender, EventArgs e)
{
button1.Text = "测试开始";
await Test();
this.button1.Text = "测试完成";
}

Task Test()
{
return Task.Run(() => //把与UI刷新无关的语句放到这个匿名委托中执行
{
Thread.Sleep(10000);
});
}
}
}
你会发现在耗时过程执行过程中也能自由地拖动窗口。

假设在异步并发过程中要修改窗口控件,那么需要使用委托来访问控件。例如:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

async void button1_Click(object sender, EventArgs e)
{
button1.Text = "测试开始";
await Test();
this.button1.Text = "测试完成";
}

Task Test()
{
return Task.Run(() => //把与UI刷新无关的语句放到这个匿名委托中执行
{
Thread.Sleep(2500);
this.button1.BeginInvoke((Action)delegate
{
this.button1.Text = "1";
});
Thread.Sleep(2500);
this.button1.BeginInvoke((Action)delegate
{
this.button1.Text = "2";
});
Thread.Sleep(2500);
this.button1.BeginInvoke((Action)delegate
{
this.button1.Text = "3";
});
Thread.Sleep(2500);
});
}
}
}

这里,在耗时的异步过程执行过程中访问了 UI 界面控件,就需要使用 BeginInvoke 委托来操作控件,使用 BeginInvoke.Invoke 委托来操作控件,这是15年前就在 .net 中有的操作规范。
No Zuo No Die 2021-08-26
  • 举报
回复 3
@以专业开发人员为伍 驴头不对马嘴,说的莫名其妙,不就是开一个后台线程吗?这样能根本解决问题吗?开始的时候是不卡了,但是整个界面可能变成挨个显示,你还能控制显卡性能咋地?
No Zuo No Die 2021-08-26
  • 举报
回复 6
@以专业开发人员为伍 ///////////我这才是正解 protected override CreateParams CreateParams //防止界面闪烁 { get { CreateParams paras = base.CreateParams; paras.ExStyle |= 0x02000000; return paras; } }
xian_wwq 2020-01-22
  • 打赏
  • 举报
回复
控件太多,如果要求必须一次加载,最好给个进度条或提示信息; 如果没有强制性要求,按照功能分个类, 在左侧加导航树,把不同的控件放到不同的Tab中去。
正怒月神 2020-01-22
  • 打赏
  • 举报
回复
引用 7 楼 wangmoxhn 的回复:
[quote=引用 6 楼 正怒月神的回复:]sp1234已经回答了。 重点就是数据读取,UI绑定这些操作,变为异步。 如果说某些sql需要优化之类的,就不细说了。 大纲还是主线程和异步分离。
人家说控件多,显示卡顿,没有说因为读取后台数据导致界面假死,你们都不审题吗[/quote] 每个人审题的侧重点,本来就有区别。 怎么断定你认为的是对的,只有等楼主确认了才知道。
正怒月神 2020-01-22
  • 打赏
  • 举报
回复
引用 7 楼 wangmoxhn 的回复:
[quote=引用 6 楼 正怒月神的回复:]sp1234已经回答了。 重点就是数据读取,UI绑定这些操作,变为异步。 如果说某些sql需要优化之类的,就不细说了。 大纲还是主线程和异步分离。
人家说控件多,显示卡顿,没有说因为读取后台数据导致界面假死,你们都不审题吗[/quote] 我不知道你明不明白。。。 主线程UI绑定数据才是导致界面卡顿的主要元凶。 所以我们说这个靠异步去解决。
wangmoxhn 2020-01-22
  • 打赏
  • 举报
回复
引用 6 楼 正怒月神的回复:
sp1234已经回答了。 重点就是数据读取,UI绑定这些操作,变为异步。 如果说某些sql需要优化之类的,就不细说了。 大纲还是主线程和异步分离。
人家说控件多,显示卡顿,没有说因为读取后台数据导致界面假死,你们都不审题吗
正怒月神 2020-01-22
  • 打赏
  • 举报
回复
sp1234已经回答了。 重点就是数据读取,UI绑定这些操作,变为异步。 如果说某些sql需要优化之类的,就不细说了。 大纲还是主线程和异步分离。
wangmoxhn 2020-01-22
  • 打赏
  • 举报
回复
楼上答非所问啊。人家问的是控件多显示卡顿,注意审题。
lich2005 2020-01-21
  • 打赏
  • 举报
回复
如果程序没毛病,界面设计合理,这种只有考虑换一台性能好点(显存,内存大些)的机子了。

111,092

社区成员

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

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

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