c#winform控件过多卡顿问题解决方案

news/2024/11/8 0:38:40/

1.窗体打开时防止窗体闪烁

//C# 窗体程序,窗体上控件过多,会导致打开程序时窗体闪烁,下面有个不错的方法
protected override CreateParams CreateParams
{
     get
     {
           CreateParams cp = base.CreateParams;
           cp.ExStyle |= 0x02000000;
           return cp;
      }

}
2.禁掉清除背景消息
protected override void WndProc(ref Message m)
{
        if (m.Msg == 0x0014) // 禁掉清除背景消息
            return;
        base.WndProc(ref m);
}
3.设置双缓存
        public Form1()
        {
            
 
            InitializeComponent();
 
            //根据我的理解,每个窗体的这地方加上以下几行代码就行了
            this.DoubleBuffered = true;//设置本窗体
            //采用双缓冲技术的控件必需的设置
            //SetStyle(ControlStyles.UserPaint, true);
            //SetStyle(ControlStyles.ResizeRedraw, true);
            //SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲
            //SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            //SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
            //SetStyle(ControlStyles.EnableNotifyMessage, true);
            //SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
 
            SetStyle(
                ControlStyles.UserPaint//使用自定义的绘制方式
                | ControlStyles.ResizeRedraw//当控件大小发生变化时就重新绘制
                | ControlStyles.DoubleBuffer// 双缓冲
                | ControlStyles.SupportsTransparentBackColor//则控件接受 alpha 组件数小于 255 个的 BackColor 来模拟透明度
                | ControlStyles.AllPaintingInWmPaint//禁止擦除背景.则控件忽略窗口消息 WM_ERASEBKGND 以减少闪烁
                | ControlStyles.EnableNotifyMessage// 
                // Enable the OnNotifyMessage event so we get a chance to filter out 
                // Windows messages before they get to the form's WndProc
                | ControlStyles.OptimizedDoubleBuffer//则控件将首先绘制到缓冲区而不是直接绘制到屏幕,这可以减少闪烁
                , true);
 
 
        }
4.界面重绘
        Image curChartImage;//为当前控件/窗体生成截图
        private void DrawRectBackImage(Control c, int xStart, int yStart, int Width, int Height)
        {
 
            Bitmap bit = new Bitmap(c.Width, c.Height);//实例化一个和窗体一样大的bitmap
            Graphics g = Graphics.FromImage(bit);
            g.CompositingQuality = CompositingQuality.HighQuality;//质量设为最高
            g.CopyFromScreen(this.Location.X +8+ c.Left, this.Location.Y+30 + c.Top, 0, 0, new Size(c.Width, c.Height));//保存整个窗体为图片
 
            curChartImage = bit;
        }
在内存中绘好图之后,绘图到界面

        int xStart = 150, yStart = 150, xWidth = 100, yHeight = 100;
        //虚拟时钟
        //在内存中保存图像,直接刷新到界面
        double num = 0;
        private void timer1_Tick(object sender, EventArgs e)
        {
 
            if (curChartImage == null)
            {
                DrawRectBackImage(panel1, xStart, yStart, 2 * xWidth, 2 * yHeight);
            }
            if (panel1.Width == 0)
                return;
            Bitmap memoryCanvas = new Bitmap(panel1.Width, panel1.Height);
            double x = xStart + xWidth * Math.Sin(num * Math.PI / 180);
            double y = yStart - yHeight * Math.Cos(num * Math.PI / 180);
 
            tsmi_tip.Text = Convert.ToString((num = num + 0.3));
 
            Graphics memDc = Graphics.FromImage(memoryCanvas);
            memDc.SmoothingMode = SmoothingMode.HighQuality;
            memDc.DrawImage(curChartImage, 0, 0, panel1.Width, panel1.Height);
 
            Pen p1 = new Pen(Color.Black, 1);
            memDc.DrawLine(p1, (float)xStart, (float)yStart, (float)x, (float)y);
 
            Graphics g = panel1.CreateGraphics();
            g.DrawImage(memoryCanvas, xStart, yStart - 20, 2 * xWidth, 2 * yHeight);
 
            panel1.BackgroundImage = memoryCanvas;
 
            memDc.Dispose();
 
        }


最近项目中使用Chat控件,根据接收到的串口数据实时绘制数据曲线,但是在绘制曲线时,绘图区闪烁严重,网上找了很多方法,都不起作用,双缓存也不起作用,最后使用

 protected override void WndProc(ref Message m)    {

            if (m.Msg == 0x0014) // 禁掉清除背景消息

                return;

            base.WndProc(ref m);

        }

成功。

使用该方法时也不能用双缓存,如果使用双缓存,该方法也不起作用,具体什么原因,还不能理解。

5、C# winform 局部刷新
做winform界面程序时,经常会遇到后台处理占用大量时间的情况,这就会造成界面假死状态。一般解决界面假死有两种方式:要么把占用大量时间的处理方式放入其他线程;要么把界面显示放入其他线程。第一种方式应该比较简单,开单独的线程,处理数据,将处理数据显示到界面就好。但是我们经常需要在主程序运算一些内容,否则可能会改动比较大。因此,这里讲讲第二种方式。
同样是使用多线程,但是c#在其他线程刷新有一点点问题,即不能跨线程操作界面。这可以使用控件的Invoke方法解决:

复制代码

private delegate void CrossThread();
Control control = ....;
CrossThread cross = delegate()
{
     control.Refresh();
};
control.Invoke(cross);
复制代码

这样可以让控件在其它线程刷新界面。

再加上开新线程后的通用方法:

复制代码

private void InvaliateControl(Control control)
{
    Thread t = new Thread(
        new ThreadStart(delegate()
        {
            CrossThread cross = delegate()
            {
                control.Refresh();
            };
            control.Invoke(cross);
        }
    ));
}
复制代码

这样就可以在任何时候,调用此方法对控件进行刷新,而不将整个界面刷新。如果对于同一个控件,连续多次刷新,可以添加一个成员变量作为标记,以免同一控件连续多次刷新,提升部分性能。

补充:在主线程调用耗时操作用此方法可能会有问题,经过验证调用Invoke函数,其实是在主线程刷新界面。

 
 


http://www.ppmy.cn/news/571888.html

相关文章

LNMP架构搭建

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、LNMP概述1.LNMP的特点2.LNMP工作原理 二、安装Nginx 服务1.安装需要的依赖包2.创建运行用户3.编译安装4.优化路径5.添加 Nginx 系统服务 三、安装mysql服务1.安…

深入理解微分、积分电路!搞懂PID控制原理就这么简单!

很多朋友觉得PID是遥不可及,很神秘,很高大上的一种控制,对其控制原理也很模糊,只知晓概念性的层面,知其然不知其所以然,那么本期从另类视角来探究微分、积分电路的本质,意在帮助理解PID的控制原…

最最简单区别iPhone是港版还是国行

要想分辨所购买iPhone是大陆行货、水货、港货还是其它,其实很简单。 下面是最简单的方法区别: 1.序列号:港版以zp/A结尾,国行以CH/A结尾.(J--日本;HK或ZP--香港;US或LL--美国;UK--英国;TA-- 台湾;CH--…

iPad 2下月登陆香港 水货应声降价

南都讯记者朱菂发自香港价格居高不下的iPad2水货市场风云突变。美国苹果公司22日说,新一代苹果平板电脑iPad2定于4月登陆中国香港、新加坡、韩国等地。不过,苹果公司没有公布iPad2香港上市的具体日期。消息传来,水货市场提前受到冲击。昨日&a…

苹果开发者 安卓开发者 谷歌广告Admob 跨境电商 海外收款和收取美金方法

转载请标明来源,谢谢。 苹果开发者和谷歌Admob用户,或者做跨境电商的小伙伴们,一般会用什么样的收款方式来收取在国外赚到的美金呢?前段时间了解了一下,在这里介绍给大家,主要有下面这几种: 一…

苹果cms v10版本搭建影视网站详细教程

为什么要搭建这个网站:因为最近闲的无聊,想追点美剧,但是自己想看的美剧在腾讯视频这些上面又没有完整的,然后去一些网站看的,要不然就是垃圾广告多,要不然就是看一会卡一会,无奈之下就决定搭建…

mac 香港购买分享

2019独角兽企业重金招聘Python工程师标准>>> 写文章的目的是给那些想去香港买Mac的同学,共享一下信息,毕竟去香港会便宜些,码代码不容易,省点钱好找媳妇。自己购买Mac的动机,之前一直喜欢Mac,碍…

苹果CMS v10详细安装教程+官方原版源码分享

苹果CMS是一款非常优秀的开源影视网站源码,已经更新了多年,功能非常齐全,用于快速搭建视频网站。 本期就开始给各位小伙伴分享,如何快速安装苹果CMS v10。 当然后续小编也会持续给大家分享视频上传、采集等相关教程,…