将 DataGridView 的行高设置为自定义值很慢
Setting the height of Rows of a DataGridView to a custom value is slow
我正在处理一个 WinForms 项目,我有一个包含 5 个数据绑定 DataGridView 控件的表单。
我需要为每一行设置自定义高度:
我使用以下代码:
private void dgv_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
dgv.SuspendLayout();
var rowHeight = CalculateRowHeight((MyDto)dgvBatches.Rows[e.RowIndex].DataBoundItem));
dgvBatches.Rows[e.RowIndex].Height = rowHeight;
dgvBatches.ResumeLayout();
}
它可以工作,但 DataGridView 加载和滚动很慢。
有什么技巧可以提高加载和滚动速度吗?
不断引发RowPrePaint事件:每次滚动DataGridView(多次),单击一个Cell(2次或更多次:1次用于Header),当您将鼠标指针悬停在1 个或多个单元格,当您更改值等时
看来Rows的高度只有在给Control分配了一个数据源的时候才需要计算,我的建议是数据绑定完成后才进行这个操作。
控件通知绑定完成,引发 DataBindingComplete 事件。
在其处理程序中,您可以暂停布局,执行所需的计算并将结果分配给添加到网格的每一行:
private void dgv_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (e.ListChangedType == ListChangedType.Reset) {
dgvBatches.SuspendLayout();
for (int i = 0; i < dgvBatches.Rows.Count - 1; i++) {
if (i == dgvBatches.NewRowIndex) continue;
var rowHeight = CalculateRowHeight((MyDto)dgvBatches.Rows[e.RowIndex].DataBoundItem));
dgvBatches.Rows[e.RowIndex].Height = rowHeight;
}
dgvBatches.ResumeLayout(false);
}
else if (e.ListChangedType == ListChangedType.ItemChanged) {
// Partner with CellValueChanged
}
}
DataBindingComplete
事件让您知道导致绑定通知的原因。
当您第一次为 DataSource
属性 赋值时,e.ListChangedType
成员将设置为 ListChangedType.Reset
,当 DataBoundItem
值更改时,它将是 ListChangedType.ItemChanged
,这样您就可以确定在这种情况下需要采取什么行动。
如果单个 Cell 值发生变化,您可能不需要重新计算所有内容,如果它完全可以更改的话。
如果确实如此,您可以调整单个行的大小,或调整当前行之后的所有行的大小,等等。
由于此布局可能会变得复杂,您还可以从双缓冲 DataGridView 中获益,除非您有 高数字 1行数(看起来不像,但可能是)。
尝试将其添加到表单构造器中,看看是否更好:
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
dgvBatches.GetType().GetProperty("DoubleBuffered", flags).SetValue(dgvBatches, true);
1 - 高数 取决于多种因素,而不仅仅是行数。当您测试网格如何响应不同形式的交互时,您知道行数是高,但您发现它没有按预期做出反应。
我正在处理一个 WinForms 项目,我有一个包含 5 个数据绑定 DataGridView 控件的表单。
我需要为每一行设置自定义高度:
我使用以下代码:
private void dgv_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
dgv.SuspendLayout();
var rowHeight = CalculateRowHeight((MyDto)dgvBatches.Rows[e.RowIndex].DataBoundItem));
dgvBatches.Rows[e.RowIndex].Height = rowHeight;
dgvBatches.ResumeLayout();
}
它可以工作,但 DataGridView 加载和滚动很慢。
有什么技巧可以提高加载和滚动速度吗?
不断引发RowPrePaint事件:每次滚动DataGridView(多次),单击一个Cell(2次或更多次:1次用于Header),当您将鼠标指针悬停在1 个或多个单元格,当您更改值等时
看来Rows的高度只有在给Control分配了一个数据源的时候才需要计算,我的建议是数据绑定完成后才进行这个操作。
控件通知绑定完成,引发 DataBindingComplete 事件。
在其处理程序中,您可以暂停布局,执行所需的计算并将结果分配给添加到网格的每一行:
private void dgv_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
if (e.ListChangedType == ListChangedType.Reset) {
dgvBatches.SuspendLayout();
for (int i = 0; i < dgvBatches.Rows.Count - 1; i++) {
if (i == dgvBatches.NewRowIndex) continue;
var rowHeight = CalculateRowHeight((MyDto)dgvBatches.Rows[e.RowIndex].DataBoundItem));
dgvBatches.Rows[e.RowIndex].Height = rowHeight;
}
dgvBatches.ResumeLayout(false);
}
else if (e.ListChangedType == ListChangedType.ItemChanged) {
// Partner with CellValueChanged
}
}
DataBindingComplete
事件让您知道导致绑定通知的原因。
当您第一次为 DataSource
属性 赋值时,e.ListChangedType
成员将设置为 ListChangedType.Reset
,当 DataBoundItem
值更改时,它将是 ListChangedType.ItemChanged
,这样您就可以确定在这种情况下需要采取什么行动。
如果单个 Cell 值发生变化,您可能不需要重新计算所有内容,如果它完全可以更改的话。
如果确实如此,您可以调整单个行的大小,或调整当前行之后的所有行的大小,等等。
由于此布局可能会变得复杂,您还可以从双缓冲 DataGridView 中获益,除非您有 高数字 1行数(看起来不像,但可能是)。
尝试将其添加到表单构造器中,看看是否更好:
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
dgvBatches.GetType().GetProperty("DoubleBuffered", flags).SetValue(dgvBatches, true);
1 - 高数 取决于多种因素,而不仅仅是行数。当您测试网格如何响应不同形式的交互时,您知道行数是高,但您发现它没有按预期做出反应。