那么,您的意思是对重复的行使用相同的随机颜色?为此,您需要按单元格值对行进行分组,并为每个组使用一种颜色。这样做是在CellPainting
事件是一项繁重的任务,因为它是为网格中的每个单元格引发的。因此,我建议添加一个隐藏的DataColumn
to the DataTable
保留每行的颜色索引。当您第一次绑定控件以及用户修改值时,会设置索引。
' +
Imports System.Reflection
Private colors As Color()
Private bmp As Bitmap
Sub New()
InitializeComponent()
' To reduce the flickering...
DataGridView1.GetType().
GetProperty("DoubleBuffered",
BindingFlags.Instance Or BindingFlags.NonPublic).
SetValue(DataGridView1, True)
End Sub
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
' Collect dark colors...
colors = GetType(Color).
GetProperties(BindingFlags.Public Or BindingFlags.Static).
Where(Function(pi) pi.PropertyType = GetType(Color)).
Select(Function(pi) CType(pi.GetValue(GetType(Color), Nothing), Color)).
Where(Function(c)
Return ((
c.R * 0.299F +
c.G * 0.587F +
c.B * 0.114F) / 256.0F) <= 0.5F
End Function).ToArray()
bmp = My.Resources.Money
Dim Table1 = New DataTable("TableName")
Table1.Columns.AddRange({
New DataColumn("Column1", GetType(String)),
New DataColumn("Column2", GetType(Integer)),
New DataColumn("Column3", GetType(Integer)),
New DataColumn("ColorIndex", GetType(Integer))
})
Table1.Rows.Add("Item1", 44, 99)
Table1.Rows.Add("Item2", 50, 70)
Table1.Rows.Add("Item3", 75, 85)
Table1.Rows.Add("Item2", 60, 70)
Table1.Rows.Add("Item3", 75, 85)
Table1.Rows.Add("Item4", 77, 21)
Table1.Rows.Add("Item2", 50, 70)
' ...etc.
DataGridView1.DataSource = Table1
DataGridView1.Columns("ColorIndex").Visible = False
UpdateColorColumn()
Table1.AcceptChanges()
End Sub
Protected Overrides Sub OnFormClosed(e As FormClosedEventArgs)
MyBase.OnFormClosed(e)
bmp.Dispose()
DirectCast(DataGridView1.DataSource, IDisposable)?.Dispose()
End Sub
Private Sub DataGridView1_CellValueChanged(sender As Object,
e As DataGridViewCellEventArgs) _
Handles DataGridView1.CellValueChanged
UpdateColorColumn()
End Sub
Private Sub DataGridView1_CellPainting(sender As Object,
e As DataGridViewCellPaintingEventArgs) _
Handles DataGridView1.CellPainting
If e.RowIndex >= 0 AndAlso e.ColumnIndex = -1 AndAlso
e.RowIndex <> DataGridView1.NewRowIndex Then
Dim ellipseSize = DataGridView1.RowTemplate.Height - 3
Dim ellipseRect = New Rectangle(
e.CellBounds.X + (e.CellBounds.Width - ellipseSize) \ 2,
e.CellBounds.Y + (e.CellBounds.Height - ellipseSize) \ 2,
ellipseSize, ellipseSize)
Dim imgSize = ellipseSize ' Or smaller...
Dim imgRect = New Rectangle(
ellipseRect.X + (ellipseRect.Width - imgSize) \ 2,
ellipseRect.Y + (ellipseRect.Height - imgSize) \ 2,
imgSize, imgSize)
Dim drv = DirectCast(DataGridView1.Rows(e.RowIndex).DataBoundItem, DataRowView)
Dim colorIndex = Convert.ToInt32(drv.Item("ColorIndex"))
Dim g = e.Graphics
Dim gs = g.Save()
e.Paint(e.ClipBounds, DataGridViewPaintParts.Background Or
DataGridViewPaintParts.Border Or
DataGridViewPaintParts.SelectionBackground)
Using ellipseBrush = New SolidBrush(colors(colorIndex))
g.SmoothingMode = SmoothingMode.AntiAlias
g.FillEllipse(ellipseBrush, ellipseRect)
g.InterpolationMode = InterpolationMode.HighQualityBicubic
g.DrawImage(bmp, imgRect, 0, 0, bmp.Width, bmp.Height,
GraphicsUnit.Pixel)
End Using
g.Restore(gs)
e.Handled = True
End If
End Sub
Private Sub UpdateColorColumn()
Dim dt = DirectCast(DataGridView1.DataSource, DataTable)
dt.EndInit()
Dim groups = dt.AsEnumerable().
GroupBy(Function(g) New With {
Key .Col1 = g.Item(0),
Key .Col2 = g.Item(1),
Key .Col3 = g.Item(2) ' Remove this to group by the first two.
})
For i = 0 To groups.Count - 1
Dim group = groups(i)
Dim colorIndex = i Mod colors.Length
For Each row In group
row("ColorIndex") = colorIndex
Next
Next
End Sub
如果您有数据库,请填写DataTable
在添加之前ColorIndex
柱子。要更新数据库,您不需要对附加列执行任何特殊操作。这INSERT
and UPDATE
命令执行它们的 SQLCommandText
查询并忽略中的任何其他内容Columns
收藏。但是,您可以获得当前版本的副本DataTable
并排除非数据库列。
例如:
Dim dt = Table1.DefaultView.
ToTable(False, Table1.Columns.
Cast(Of DataColumn).
Where(Function(c) c.ColumnName <> "ColorIndex").
Select(Function(c) c.ColumnName).ToArray())
作为另一种选择,使用DataGridViewRow.Tag
属性来保持颜色索引。同样可以这样写。
Private colors As Color()
' ...
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
' ...
DataGridView1.DataSource = Table1
UpdateColorIndices()
End Sub
' ...
Private Sub DataGridView1_CellPainting(sender As Object,
e As DataGridViewCellPaintingEventArgs) _
Handles DataGridView1.CellPainting
If e.RowIndex >= 0 AndAlso e.ColumnIndex = -1 AndAlso
e.RowIndex <> DataGridView1.NewRowIndex Then
Dim ellipseSize = DataGridView1.RowTemplate.Height - 3
Dim ellipseRect = New Rectangle(
e.CellBounds.X + (e.CellBounds.Width - ellipseSize) \ 2,
e.CellBounds.Y + (e.CellBounds.Height - ellipseSize) \ 2,
ellipseSize, ellipseSize)
Dim imgSize = ellipseSize
Dim imgRect = New Rectangle(
ellipseRect.X + (ellipseRect.Width - imgSize) \ 2,
ellipseRect.Y + (ellipseRect.Height - imgSize) \ 2,
imgSize, imgSize)
Dim colorIndex = Convert.ToInt32(DataGridView1.Rows(e.RowIndex).Tag)
Dim g = e.Graphics
Dim gs = g.Save()
e.Paint(e.ClipBounds, DataGridViewPaintParts.Background Or
DataGridViewPaintParts.Border Or
DataGridViewPaintParts.SelectionBackground)
Using ellipseBrush = New SolidBrush(colors(colorIndex))
g.SmoothingMode = SmoothingMode.AntiAlias
g.FillEllipse(ellipseBrush, ellipseRect)
g.InterpolationMode = InterpolationMode.HighQualityBicubic
g.DrawImage(bmp, imgRect, 0, 0, bmp.Width, bmp.Height,
GraphicsUnit.Pixel)
End Using
g.Restore(gs)
e.Handled = True
End If
End Sub
Private Sub UpdateColorIndices()
DataGridView1.EndEdit()
Dim groups = DataGridView1.Rows.Cast(Of DataGridViewRow).
Where(Function(r) r.Index <> DataGridView1.NewRowIndex).
GroupBy(Function(r) New With {
Key .Col0 = r.Cells(0).Value,
Key .Col1 = r.Cells(1).Value,
Key .Col2 = r.Cells(2).Value
})
For i = 0 To groups.Count - 1
Dim index = i Mod colors.Length
For Each row In groups(i)
row.Tag = index
Next
Next
DataGridView1.Invalidate()
End Sub
另外,您可以创建一个Dictionay(Of Integer, Color)
其中每个KeyValuePair
保存行索引和椭圆颜色。
Private colors As Color()
Private ReadOnly dictColors As New Dictionary(Of Integer, Color)
' ...
Private Sub DataGridView1_CellPainting(sender As Object,
e As DataGridViewCellPaintingEventArgs) _
Handles DataGridView1.CellPainting
If e.RowIndex >= 0 AndAlso e.ColumnIndex = -1 AndAlso
e.RowIndex <> DataGridView1.NewRowIndex Then
Dim ellipseSize = DataGridView1.RowTemplate.Height - 3
Dim ellipseRect = New Rectangle(
e.CellBounds.X + (e.CellBounds.Width - ellipseSize) \ 2,
e.CellBounds.Y + (e.CellBounds.Height - ellipseSize) \ 2,
ellipseSize, ellipseSize)
Dim imgSize = ellipseSize
Dim imgRect = New Rectangle(
ellipseRect.X + (ellipseRect.Width - imgSize) \ 2,
ellipseRect.Y + (ellipseRect.Height - imgSize) \ 2,
imgSize, imgSize)
Dim g = e.Graphics
Dim gs = g.Save()
e.Paint(e.ClipBounds, DataGridViewPaintParts.Background Or
DataGridViewPaintParts.Border Or
DataGridViewPaintParts.SelectionBackground)
Using ellipseBrush = New SolidBrush(dictColors(e.RowIndex))
g.SmoothingMode = SmoothingMode.AntiAlias
g.FillEllipse(ellipseBrush, ellipseRect)
g.InterpolationMode = InterpolationMode.HighQualityBicubic
g.DrawImage(bmp, imgRect, 0, 0, bmp.Width, bmp.Height,
GraphicsUnit.Pixel)
End Using
g.Restore(gs)
e.Handled = True
End If
End Sub
Private Sub UpdateColorIndices()
DataGridView1.EndEdit()
dictColors.Clear()
Dim groups = DataGridView1.Rows.Cast(Of DataGridViewRow).
Where(Function(r) r.Index <> DataGridView1.NewRowIndex).
GroupBy(Function(r) New With {
Key .Col0 = r.Cells(0).Value,
Key .Col1 = r.Cells(1).Value,
Key .Col2 = r.Cells(2).Value
})
For i = 0 To groups.Count - 1
Dim index = i Mod colors.Length
For Each row In groups(i)
dictColors(row.Index) = colors(index)
Next
Next
DataGridView1.Invalidate()
End Sub