DataGridView虚拟模式,更新RowCount会导致CellValueNeeded事件触发所有行。

6

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

DataGridView grid = new ...;

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

我该如何告诉网格只请求显示的行?
5个回答

6

这只是一个猜测,但您是否将AutoSizeRowsMode或AutoSizeColumnsMode的值设置为AllCells,或者任何列也设置为该值?尝试将调整大小模式设置为None或仅为DisplayedCells,看看是否仍存在问题。


不幸的是,grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;grid.Columns.ForEach(col => col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None) 不会改变这种行为。 - Firo

5

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

我注意到滚动条在“缓慢”更改; 即它看起来像在逐个删除我的虚拟行!

无论如何,在每次调用grid.RowCount = n之前进行grid.Rows.Clear()显着提高了性能。


我的问题是 grid.RowCount = n 会立即调用所有行的 OnCellValueNeeded,即使它们没有被显示。 - Firo
这并没有回答原问题,但解决了我的性能问题。谢谢! - Kuba
我也遇到了同样的问题。我正在使用 RowCount=0 的解决方案,因为在不使用它时,从例如 RowCount=10000RowCount=2 时设置 RowCount 需要10秒以上的时间,但请注意,当使用此解决方案时,还必须手动恢复选择。我希望 netfx 在 RowCount.set() 中对 value!=0 不使用循环... - binki

2
在设置完整计数之前,您应将 RowCount 设置为零。
DataGridView grid = new ...;
grid.VirtualMode = true;
grid.CellValueNeeded += OnCellValueNeeded;
grid.RowCount = 0;
grid.RowCount = dataprovider.GetFullCount();

我的问题是grid.RowCount = dataprovider.GetFullCount()会立即调用所有行的OnCellValueNeeded,即使它们没有被显示。尝试将RowCount设置为1000,只有一列,并在OnCellValueNeeded中使用Thread.Sleep(100); e.Value = "Something;" - Firo
1
在设置另一个计数之前将 RowCount 设置为零可以防止对所有行调用 OnCellValueNeeded。你可以试试,这对我很有效。 - Cem Mutlu
这似乎与 https://social.msdn.microsoft.com/Forums/windows/en-US/c823a522-56f5-451b-9d5e-bdeac8833eeb/speeding-up-setting-of-datagridviewrowcount?forum=winformsdatacontrols 的建议相符。但除了 .netfx 有点古怪之外,没有人说为什么这样做会起作用? - binki
当网格处于虚拟模式时,是否有可能按特定列进行过滤?假设我在某些列中输入文本,只显示匹配的记录,并使网格显示这些匹配的记录,而不仅仅是当前在网格中显示的数据。 - Arie

1

不幸的是,这似乎是标准行为。我可以通过以下方式解决它

void OnCellValueNeeded(...)
{
    if(!_active) return;
}

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

或者在后台线程中实现带有复杂懒加载的IBindingList、ITypedList接口

更新: 问题似乎已经解决。我使用以下方法再也无法复现它:

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";
    }
}

1
确保您没有将列自动调整大小模式设置为allcells。 - Marcin
没有任何区别,详见我在 https://dev59.com/d17Va4cB1Zd3GeqPFgLR#8404739 上的评论。 - Firo
@VisakhVA 什么不起作用:我的解决方法还是它在你的机器上没有神奇地修复? - Firo

0

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

这两个方法都提高了性能,但都没有让它足够快速,因为我正在实时根据搜索框中的输入动态过滤网格。

我找到了另外两个解决方案:

1)使用分页,这样您就不必一开始就将RowCount设置得太高。如果您已经使用分页(在这种情况下,您就不会在这里),那么我认为这是一个很好的解决方案,但如果您没有计划实施它,则过于繁琐。

2)将设置RowCount的调用放在自己的线程中。这是我即将尝试的方法。老实说,如果您在线程仍在完成时尝试编辑单元格,我不确定这个方法有多安全,但我想我很快就会发现。

编辑:

好的,所以我尝试了线程,希望这样做可以解决问题,因为我在其他地方读到它确实帮助了另一个人。如果你只是偶尔更改值,那么它似乎是一个很好的解决方案,但如果你连续多次更改值,它仍然会挂起(我正在这样做)。我认为这是因为你必须使用Invoke(),第二次它仍然在等待第一次完成。我不能说我完全理解其中的问题,但我已经决定暂时接受空行,因为当我把它们留在那里时,速度快得多,也不那么复杂。


请求数据和接收数据之间总是存在延迟。具有临时空单元格的响应式用户界面是我能想象到的最佳用户体验,因为如果所请求的数据不是用户真正想要的数据(例如,他只是滚动),那么这并不重要。 - Firo
1
@Firo 是的。我只是觉得当你降低记录数时,它实际上仍然会在更新计数之前尝试获取超过你设置的计数的记录的值,这真是太愚蠢了。更重要的是,为什么它甚至还在尝试获取屏幕上根本没有显示的记录的值呢?我仍然认为DGV是微软提供给我们的最伟大、最棒的控件之一,但他们肯定可以把它的这部分做得更好一些。 - BVernon
你如何按特定列进行筛选?你能分享一些代码或其他吗?你的筛选器是否适用于所有数据,而不仅仅是显示的数据? - Arie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接