关于c#:datagridview虚拟模式,更新RowCount会导致所有行都触发CellValueNeeded

datagridview virtual mode, update RowCount causes CellValueNeeded to fire for all rows

我正在尝试实现datagridview的虚拟模式,但是当我将RowCount设置为某个数字(以显示滚动条)时,网格希望一次拥有所有行,而不仅仅是显示的行。

1
2
3
4
5
DataGridView grid = new ...;

grid.VirtualMode = true;
grid.CellValueNeeded += OnCellValueNeeded;
grid.RowCount = dataprovider.GetFullCount();

如何告诉网格仅请求显示的行?


这只是一个猜测,但是您是否已将AutoSizeRowsMo??de或AutoSizeColumnsMode值设置为AllCells或将任何列设置为该值?尝试将调整大小模式设置为"无"或仅设置为" DisplayedCells",然后查看是否仍然存在问题。


不确定这是否与我遇到的问题相同,但是当定期大幅度更改VirtualMode DataGridView上的RowCount时,我的确获得了非常差的性能。

我注意到滚动条在"缓慢地"变化;即看起来好像是在个别删除我的虚拟行(!)。

无论如何,在每次调用grid.RowCount = n之前执行grid.Rows.Clear()都会大大提高性能。


在设置完整计数之前,应将RowCount设置为零。

1
2
3
4
5
DataGridView grid = new ...;
grid.VirtualMode = true;
grid.CellValueNeeded += OnCellValueNeeded;
grid.RowCount = 0;
grid.RowCount = dataprovider.GetFullCount();


不幸的是,这似乎是标准行为。我可以通过

解决

1
2
3
4
5
6
7
8
9
10
void OnCellValueNeeded(...)
{
    if(!_active) return;
}

grid.VirtualMode = true;
grid.CellValueNeeded += OnCellValueNeeded;
_active = false;
grid.RowCount = dataprovider.GetFullCount();
_active = true;

或在后台线程中使用复杂的懒惰获取实现IBindingList,ITypedList

更新:问题现在似乎已解决。我无法使用以下命令重现它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
static class Program
{
    private static Form form;
    private static int i;

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        var grid = new DataGridView
        {
            Dock = DockStyle.Fill,
            VirtualMode = true,
            AllowUserToAddRows = false,
            Columns =
            {
                new DataGridViewTextBoxColumn { HeaderText ="foo" },
                new DataGridViewTextBoxColumn { HeaderText ="bar" },
            },
        };
        grid.CellValueNeeded += OnCellValueNeeded;
        form = new Form
        {
            Controls = { grid }
        };

        //grid.RowCount = 0;
        grid.RowCount = 10000;

        Application.Run(form);
    }

    private static void OnCellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
    {
        i++;
        form.Text = i.ToString();
        e.Value ="fooValue";
    }
}


我遇到了同样的问题,并且像您一样尝试了设置活动标志的解决方案,并且还尝试了在设置新标志之前将RowCount设置为0(或grid.Rows.Clear())的解决方案。 RowCount。

这两种方法都提高了性能,但都没有对其进行足够的改进以使其达到我想要的即时性,因为我正在根据搜索框的输入实时动态地过滤网格。

我发现了另外两个解决方案:

1)使用分页,这样一来您就不必将RowCount设置得很高。如果您已经在使用分页(在这种情况下您就不会在这里了),那么我认为这是一个很好的解决方案,但是如果您不打算实现它,那么这将是一个过于繁琐的解决方案。

2)将调用置于其自己的线程中以设置RowCount。这是我要尝试的。坦率地说,如果您在线程仍在结束时尝试编辑单元格,则不确定此代码的安全性,但是我想我会很快发现的。

编辑:

好的,所以我尝试将其线程化,希望能达到目的,因为我在其他地方读到它确实对另一个人有所帮助。如果您只是偶尔更改一次值,这似乎是一个很好的解决方案,但是如果您连续多次(我是这样),它仍然会挂起。我认为这是因为您必须使用Invoke(),并且第二次仍在等待第一个完成。不能说我完全理解这笔交易是什么,但是我决定暂时只使用空白行,因为当我将它们留在那里时,它的SOOO更快,更简单。