C# DataGridView仅在行大致适合一页时闪烁

C# DataGridView仅在行大致适合一页时闪烁,c#,winforms,datagridview,C#,Winforms,Datagridview,我有一个尽可能基本的网格视图。它显示一个一次性的搜索结果,除非再次单击搜索按钮,否则不会更新其数据源,因此我认为数据更新不会导致问题 例如,我的搜索返回30行结果,我的全屏数据网格可以容纳40行而不滚动,没有闪烁。然后我开始慢慢地降低窗户的高度。一旦栅格视图高度略低于我的30行高度,它就会开始闪烁。但如果我进一步降低窗口的高度,使网格视图只能显示20行,则会显示一个滚动条,一切正常。即使向上或向下滚动也不会闪烁 虽然我不认为这与性能有关,但我尝试过像暂停布局和双缓冲这样的方法,但并没有如预期的那

我有一个尽可能基本的网格视图。它显示一个一次性的搜索结果,除非再次单击搜索按钮,否则不会更新其数据源,因此我认为数据更新不会导致问题

例如,我的搜索返回30行结果,我的全屏数据网格可以容纳40行而不滚动,没有闪烁。然后我开始慢慢地降低窗户的高度。一旦栅格视图高度略低于我的30行高度,它就会开始闪烁。但如果我进一步降低窗口的高度,使网格视图只能显示20行,则会显示一个滚动条,一切正常。即使向上或向下滚动也不会闪烁

虽然我不认为这与性能有关,但我尝试过像暂停布局和双缓冲这样的方法,但并没有如预期的那样有所帮助

我认为当它接近边界条件时,它与自动行高计算有关,但我不知道如何解决它。以下是自动行大小设置,可能/可能不会影响它

dgv.DataSource = datatable;
dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
dgv.Sort(dgv.Columns["Creation Date"], ListSortDirection.Ascending);
dgv.Columns["Creation Date"].SortMode = DataGridViewColumnSortMode.Automatic;
dgv.Columns["Name"].SortMode = DataGridViewColumnSortMode.Automatic;
dgv.Columns["Name"].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dgv.Columns["Name"].DefaultCellStyle.WrapMode = DataGridViewTriState.True;
dgv.Columns["Receipt No."].SortMode = DataGridViewColumnSortMode.Automatic;
dgv.Columns["Receipt No."].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dgv.Columns["Receipt No."].DefaultCellStyle.WrapMode = DataGridViewTriState.True;
dgv.Columns["Remark"].DefaultCellStyle.WrapMode = DataGridViewTriState.True;
dgv.Columns["Remark"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
这是我的双缓冲类,以防我搞砸了

public static class BufferedGridView
{
    public static void DoubleBuffered(this DataGridView dgv, bool setting)
    {
        Type dgvType = dgv.GetType();
        PropertyInfo pi = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
        pi.SetValue(dgv, setting, null);
    }
}
这就是我使用它的地方,以包含网格视图的形式

public ManagementPage()
{
    InitializeComponent();

    dgv.DoubleBuffered(true);
    .......
}

我遇到了这个问题,经过一些分析后得出结论,这是.NET中的一个缺陷,发生在edge情况下,DataGridView的高度与它需要包含的行大致相同,这是因为添加垂直滚动条、调整行高度、然后删除滚动条等无休止的循环


我在这里发布了我提出的解决方案:

为了回应下面的评论,我在下面再次列出了答案。对不起,我对这个网站相当陌生-只是想帮你

似乎可以通过覆盖OnCellValueChanged和OnRowHeightChanged事件来打破导致闪烁的无休止循环:

protected override void OnCellValueChanged(DataGridViewCellEventArgs e)
{
    if (e.RowIndex != -1)
    {
        this.Rows[e.RowIndex].MinimumHeight = 2;
    }
    
    base.OnCellValueChanged(e);
}

这基本上将最小行高锁定为行高更新时的高度,然后在单元格值更改时释放它


因此,当内部DataGridView代码尝试调整行的大小时,它们会被锁定到最小值(这意味着它们不会再次减小大小,这就是导致无休止循环的原因)。当用户(或代码)更新单元格时,会释放此约束,以便行可以在需要时调整大小。

首先要检查的是各种事件中的代码,这些事件无效或类似,然后导致再次调用该事件。例如,修补所有行的for循环我仔细检查了每个事件是否都附加到一个按钮(搜索按钮以更新网格视图等),并且在任何地方都没有触发自定义事件。除了我需要将搜索到的数据导出为PDF格式外,任何地方似乎都没有循环,PDF格式也附在一个按钮上。滚动或调整大小时触发的唯一事件是datagridview中的默认事件。您到底是如何进行双缓冲的?我坚信它一定会有帮助。用缓冲区代码更新。我不知道该怎么说,但缓冲不是因为处理时间长(例如,大量数据或繁重的数据计算)而有助于消除闪烁吗?在我的例子中,即使只有20条记录,只有几列,也会发生这种情况,直接从数据表中显示原始字符串数据,而不进行处理
protected override void OnRowHeightChanged(DataGridViewRowEventArgs e)
{
    e.Row.MinimumHeight = e.Row.Height;

    base.OnRowHeightChanged(e);
}