【发布时间】:2011-08-10 07:00:14
【问题描述】:
我想以虚拟模式在 datagridview 中显示“大量大量数据”。
我使用一个缓冲区来存储 n (2) 页数据,最初 2 个第一页存储在缓冲区中。当gridview滚动到缓冲区中不存在的行时,我加载当前的新页面并将其与旧页面交换。
为了模拟将大量数据从数据库加载到缓冲区中,我添加了这一行:
System.Threading.Thread.Sleep(3000);
结果,当缓冲区更新自身时,网格在这段时间内被冻结。
现在,据我了解,在这里添加线程无济于事,因为只有当滚动到达无缓冲行时才会发生 1 个操作。
private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = theBuffer.ReturnFromBuffer(e.RowIndex, e.ColumnIndex);
//I check there if row index is in buffer and if not i update the buffer with new page and return the value
}
所以我正在考虑当它发生时在网格上方添加一个“纺车”动画。
我尝试将事件发送到表单以在更新缓冲区的方法中显示/隐藏图像:
if (ProgressEvent != null)
ProgressEvent(true);
System.Threading.Thread.Sleep(3000);
if (ProgressEvent != null)
ProgressEvent(false);
并在表单事件处理程序上设置了图像的可见属性,但结果并不像预期的那样,我猜睡眠发生在事件处理之前,所以图像在睡眠之前没有出现。
所以我想还是需要胎面的。但不知道什么时候应该开始,应该怎么做?
更新:
我厌倦了建议的后台工作人员:
在 CellValueNeeded 事件调用的方法中,我检查请求的行是否被缓冲,如果没有,我启动后台工作程序。
if (!bgWorker.IsBusy) //otherwise worker will be started for every column of the row
{
bgWorker.DoWork += (sender, e) =>
{
UpdateBuffer(rowIndex);
};
bgWorker.RunWorkerAsync();
}
return "null";
还有这个:
bgWorker.RunWorkerCompleted += (sender, e) =>
{
if (IvalidateEvent != null)
IvalidateEvent(); //send event to form, where invalidate the gridview dataGridView1.Invalidate();
};
它可以工作,但有一些问题: 1)我的网格中有很多虚拟结果,即使时间不长 - 我不太喜欢它。 2)如果我保持原样,它甚至会花费更多时间,可能是因为 backgroundworker 消耗了一些时间,并且因为我实际上使网格无效并调用 CellValueNeeded 事件 2 次(第一次启动 backgroundworkerm 在完成它的工作时第二次)!
【问题讨论】:
-
使整个网格无效有点像“矫枉过正”......它还将重新绘制所有具有正确值的单元格,而不仅仅是那些带有假人的单元格。在滚动网格时避免虚拟值的另一种方法是对滚动本身做出反应。尝试在请求之前获取接近显示行的行,在这种情况下,值可能会在 CellNeedsValue 请求它们之前就在那里
-
@DarkSquirrel42,CellNeedsValue 不仅缓冲所需的行,还缓冲前面的一堆行。当我需要加载新行时唯一的问题。我不介意冻结网格,但动画必须在它发生时出现。没有虚拟值
-
当 datagridview 引发 cellvalueneeded 时,您可以指定要在单元格中显示的值。如果您没有该值,则无法指定它。所以你有2个选择:1)要么提供“加载”消息,要么什么都不提供(空字符串),在异步操作中填充缓冲区,当数据准备好时更新单元格。或选项 2) 同步填充缓冲区并返回所需的值。当然,选项 2 会阻塞 UI 线程,因此无法使用加载动画、表单重绘或用户交互(除非您执行 Application.DoEvents 之类的坏事——调试起来会很痛苦)
-
问题在于,例如,当我多次单击 pagedown 时,虚拟值会填充很多行(直到加载数据)。为了测试,我使用数据集作为源和数据表,将页面保存在内存中。也许其他资源会更快?
-
我不这么认为...尝试优化加载器进程...创建一个类来处理对需要加载数据的缓冲区的请求...存储此类请求以及何时您的工作线程运行,尝试收集不止一行(减少查询数量)......当工作人员完成工作时,让它查看请求列表并继续使用该工作人员而不是产生新工作人员,如果还有更多做... 跟踪滚动事件并确保下一个和上一个 X 行都在缓冲区中(因此滚动缓冲区后可以直接提供值)
标签: c# winforms multithreading datagridview