我正在尝试自定义 WinForms DataGridView 中的某些单元格,但遇到了一个问题,即绘画事件不断地一遍又一遍地永远触发,即使不滚动行时也是如此。基本上,当启动应用程序时,它确实会执行它应该执行的所有操作,但会出现持续闪烁,并且需要近 20 秒才能绘制整个 GUI。由于显而易见的原因,这并不理想。
我能够通过向 DataGridView 添加双缓冲来消除闪烁,但这只是掩盖了问题,因为它仍然在后台不断重绘。我不知道我的代码是否有问题,或者是表单中的错误,但如果我只是使用
DataGridViewAdvancedCellBorderStyle
设置 Single
那么问题就不会发生。仅当我尝试执行多个操作或使用不同的边框样式时才会出现这种情况。例如,仅 Inset
和 Outset
边框样式会导致重绘/闪烁,就像仅更改字体一样。
基本的想法是,我想每隔这么多行模仿“标题”,这些行看起来与普通行不同。我只使用单个列,因此在某种程度上我试图使 DataGridView 看起来更像 ListView,其中行之间没有边框。但不同的是,每 20-30 行都可以有假标题。我还想做一些其他事情,例如更改“假标题”的背景颜色,但我想我现在会尝试寻求帮助,因为我几乎不知所措。任何建议将不胜感激!
private void dataList_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
DataGridView dataList = ((DataGridView)(sender));
DataGridViewRow dataListRow = dataList.Rows[e.RowIndex];
DataGridViewCell dataListCell = dataListRow.Cells[e.ColumnIndex];
string dataTitle = dataListCell.Value.ToString();
char firstChar = dataTitle.ToCharArray()[0];
Font lineFont = dataList.Font;
float fontSize = lineFont.Size + (float)2.25;
FontFamily fontFamily = lineFont.FontFamily;
if (firstChar == '=')
{
dataListRow.Height = 26;
lineFont = new Font(fontFamily, fontSize, FontStyle.Bold, GraphicsUnit.Point);
dataListCell.Style = new DataGridViewCellStyle { Font = lineFont };
e.AdvancedBorderStyle.All = DataGridViewAdvancedCellBorderStyle.Single;
}
else
{
e.AdvancedBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
}
}
好吧,我找到了一个更好的方法来解决这个问题。通过
CellPainting
事件可以完成的唯一事情是将边框绘制为 Single
,而不会进入无限绘制循环。我没有尝试更改此处的属性,而是选择更改高度并在填充单元格时对其应用 DataGridViewCellStyle
。
for (int i = 0; i < dataSheet.Count(); i++)
{
string dataTitle = dataSheet[i];
char[] titleArray = dataTitle.ToCharArray();
if (titleArray[0] == '=')
{
string newTitle = "";
foreach (char titleChar in titleArray)
{
if (titleChar != '=')
{
newTitle += titleChar;
}
}
dataTitle = newTitle;
}
dataList.Rows.Add(dataTitle);
DataGridViewRow dataListRow = dataList.Rows[i];
DataGridViewCell dataListCell = dataListRow.Cells[0];
Font listFont = dataList.Font;
float fontSize = listFont.Size + (float)2.25;
FontFamily fontFamily = listFont.FontFamily;
dataListRow.Height = 26;
dataListCell.Style = new DataGridViewCellStyle()
{
Alignment = DataGridViewContentAlignment.MiddleCenter,
BackColor = SystemColors.Menu,
Font = new Font(fontFamily, fontSize, FontStyle.Bold, GraphicsUnit.Point),
ForeColor = SystemColors.WindowText,
SelectionBackColor = SystemColors.Highlight,
SelectionForeColor = SystemColors.HighlightText
};
}
不是检查
CellPainting
事件中字符串的第一个字符,而是已知 BackColor
,因为它不会像正常细胞一样是白色的,所以我将其用于检测方法。
// Use the style to filter out the correct nodes.
DataGridViewCellStyle dataListStyle = dataListCell.Style;
// Now check the style backcolor.
if (dataListStyle.BackColor == SystemColors.Menu)
{
// Set the border style to show the border.
e.AdvancedBorderStyle.All = DataGridViewAdvancedCellBorderStyle.Single;
}
else
{
// Remove the border for game titles.
e.AdvancedBorderStyle.All = DataGridViewAdvancedCellBorderStyle.None;
}
我感谢那些发表评论的人,让我知道我在绘画活动中试图这样做的方向是错误的。这让我发现样式可以在每个单元格的基础上应用,并且行高可以单独更改。通过在创建行后更改大多数属性的新方法,绘制事件只需要担心绘制单元格周围的边框,这是它在不永远运行的情况下可以做的唯一事情。