我正在尝试实现datagridview的虚拟模式,但是当我将RowCount设置为某个数字(以显示滚动条)时,网格希望一次性获取所有行,而不仅仅是显示的行。
DataGridView grid = new ...;
grid.VirtualMode = true;
grid.CellValueNeeded += OnCellValueNeeded;
grid.RowCount = dataprovider.GetFullCount();
我该如何告诉网格只请求显示的行?
我正在尝试实现datagridview的虚拟模式,但是当我将RowCount设置为某个数字(以显示滚动条)时,网格希望一次性获取所有行,而不仅仅是显示的行。
DataGridView grid = new ...;
grid.VirtualMode = true;
grid.CellValueNeeded += OnCellValueNeeded;
grid.RowCount = dataprovider.GetFullCount();
这只是一个猜测,但您是否将AutoSizeRowsMode或AutoSizeColumnsMode的值设置为AllCells,或者任何列也设置为该值?尝试将调整大小模式设置为None或仅为DisplayedCells,看看是否仍存在问题。
不确定这是否与我之前遇到的问题相同,但是当定期大幅更改VirtualMode DataGridView的RowCount时,我的性能确实非常差。
我注意到滚动条在“缓慢”更改; 即它看起来像在逐个删除我的虚拟行!
无论如何,在每次调用grid.RowCount = n之前进行grid.Rows.Clear()显着提高了性能。
grid.RowCount = n
会立即调用所有行的 OnCellValueNeeded,即使它们没有被显示。 - FiroRowCount=0
的解决方案,因为在不使用它时,从例如 RowCount=10000
到 RowCount=2
时设置 RowCount
需要10秒以上的时间,但请注意,当使用此解决方案时,还必须手动恢复选择。我希望 netfx 在 RowCount.set()
中对 value!=0
不使用循环... - binkiDataGridView 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不幸的是,这似乎是标准行为。我可以通过以下方式解决它
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";
}
}
我遇到了同样的问题,我尝试了像你一样设置一个活动标志的解决方案,还尝试了在设置新的RowCount之前将RowCount设置为0(或grid.Rows.Clear())的解决方案。
这两个方法都提高了性能,但都没有让它足够快速,因为我正在实时根据搜索框中的输入动态过滤网格。
我找到了另外两个解决方案:
1)使用分页,这样您就不必一开始就将RowCount设置得太高。如果您已经使用分页(在这种情况下,您就不会在这里),那么我认为这是一个很好的解决方案,但如果您没有计划实施它,则过于繁琐。
2)将设置RowCount的调用放在自己的线程中。这是我即将尝试的方法。老实说,如果您在线程仍在完成时尝试编辑单元格,我不确定这个方法有多安全,但我想我很快就会发现。
编辑:
好的,所以我尝试了线程,希望这样做可以解决问题,因为我在其他地方读到它确实帮助了另一个人。如果你只是偶尔更改值,那么它似乎是一个很好的解决方案,但如果你连续多次更改值,它仍然会挂起(我正在这样做)。我认为这是因为你必须使用Invoke(),第二次它仍然在等待第一次完成。我不能说我完全理解其中的问题,但我已经决定暂时接受空行,因为当我把它们留在那里时,速度快得多,也不那么复杂。
grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
和grid.Columns.ForEach(col => col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None)
不会改变这种行为。 - Firo