非常频繁地更新datagridview

Posted

技术标签:

【中文标题】非常频繁地更新datagridview【英文标题】:update datagridview very frequently 【发布时间】:2017-05-25 16:21:11 【问题描述】:

我无法在 C# 的合理时间内刷新我的 DataGridView(顺便说一句,我是新手,我已经习惯了 java...)。

我正在通过每秒发送 20 个包的网络获取数据。我想解析数据并将其放入 DataGridView 中。我还想调整 DataGridView 更新的时间间隔,从 0.1 秒到 1 分钟。

所以我创建了一个额外的线程,它读取包并将它们解析为一个数组。我还有一个计时器,我用它来更改间隔。在每个计时器滴答声中,我将 DataSource 重新分配给 DataGridView。

有趣的是,当我这样做时,即使我将计时器设置为 0.1 秒,它也只会每秒触发一次。如果我不刷新 DataGridView,它会按预期每秒触发 10 次。

所以我假设我更新 DataGridView 的方法太耗时了。但是我要怎么做才能让它更有效率,所以我可以每秒更新 10 次而没有任何问题呢?

这是我使用的代码:

public MyForm()
    
        InitializeComponent();

        timer = new System.Windows.Forms.Timer();
        timer.Interval = (1 * 1000); // 1 secs
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();

        readNetworkValues = true;
        networkReader = new Thread(() =>
        
            Thread.CurrentThread.IsBackground = true;
            byte[] data = new byte[1024];
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 49003);
            UdpClient newsock = new UdpClient(ipep);
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

            while (readNetworkValues)
            
                data = newsock.Receive(ref sender);
                dataSet = parseData(data); //Decrypts the data
            
        newsock.Close();
        );
        networkReader.Start();
    

    private void timer_Tick(object sender, EventArgs e)
    
        if (dataSet != null)
        
            lock (dataSet)
            
                int currentRow = dataGrid.FirstDisplayedScrollingRowIndex;
                dataGrid.DataSource = dataSet;
                dataGrid.FirstDisplayedScrollingRowIndex = currentRow;
            
        
    

【问题讨论】:

timer.Interval = (1 * 1000); // 10 秒 不。 - 另外:请勿致电DataGridViewa GridViewDataGrid,反之亦然!!这是错误且令人困惑的,因为它们是不同的控件。始终以正确的名称称呼事物! - 另外:您要显示多少数据? 20 fps 比电影快;没有人能以这样的速度阅读任何东西! 对不起,我更正了我的问题,评论是一些旧代码的遗留问题。我不知道有这样的混乱,一开始就找不到 GridView。如前所述,我对 C# 完全陌生。 20fps 不是我的目标,但正如问题中所写,我希望至少有 10fps。我知道这很快,需要的是实时可见的数据更改。在大多数情况下,1 秒太慢了。除了我目前的问题,我还想知道究竟是什么导致了“滞后”,只是为了更好地学习和了解 C#。 GridView 和 DataGrid 是来自其他/旧框架(.Net 1.0、ASP、WPF)的控件。 - 延迟可能是由数据大小引起的。你显示多少数据。或者通过锁.. 啊,很高兴知道......到目前为止,我已经用 20 行和 26 列测试了它,每列都包含一个相当短的字符串或双精度。我想将其扩展到大约 150 行,相同数量的列。我读过 C# 是相当线程安全的......锁是多余的吗? 哇,真是天才。我最终使用了这个奇怪的东西:typeof(DataGridView).InvokeMember("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, dataGrid, new object[] true ); 因为我不确定如何制作自定义类的 dataGrid ...如果您对此了解更多,如果您能详细说明为什么这在答案中有效,我将不胜感激.如果没有,无论如何都将其发布为答案,这样您就可以获得当之无愧的积分。非常感谢! 【参考方案1】:

您想要更新的单元格数量以及您想要的更新率足够高,足以导致闪烁滞后

为避免这种情况,您可以为DataGridView 启用DoubleBuffering

默认情况下不公开此属性。所以可以选择一个

创建子类或 通过反射访问它

Here is a post 演示了前者。它是针对滚动闪烁的情况而编写的,但也有助于避免更新滞后。该类可能如下所示:

public class DBDataGridView : DataGridView

    public new bool DoubleBuffered
    
        get  return base.DoubleBuffered; 
        set  base.DoubleBuffered = value; 
    

    public DBDataGridView()
    
        DoubleBuffered = true;
    

您可以将此类添加到项目中,也可以简单地添加到表单类中(在最后一个卷曲之前)。编译它会显示在工具箱中。

另一个选项使用反射;这是一个通用函数,适用于任何类型的控件:

using System.Reflection;

static void SetDoubleBuffer(Control ctl, bool DoubleBuffered)

    typeof(Control).InvokeMember("DoubleBuffered", 
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, 
        null, ctl, new object[]  DoubleBuffered );

两种方式让你随意打开和关闭DoubleBuffering;前者通过现在公开的属性,后者通过方法的bool 参数。

【讨论】:

这对我来说是一个非常有用的信息。谢谢@TaW。

以上是关于非常频繁地更新datagridview的主要内容,如果未能解决你的问题,请参考以下文章

太频繁地更新访问令牌是不好的做法吗?

OnPaint 更新太频繁

频繁更新 SQLite DB 和 Listview(效率)

SQL 和 VB.net winform 的批量更新概念

如何频繁更新顶点缓冲区数据(每帧)opengl [重复]

Qt & OpenGL:如何尽可能频繁地渲染?