Introduction
Sometimes it's useful to graphically show the value of a column in a DataGridView
so the user can compare rows easily. This is an example of implementing this on any DataGridView
by only calling a shared class method from the DataGridView
's CellPainting
event, as I've described in my blog http://ensamblareficiente.blogspot.com (Spanish).
Using the Code
The project shows, in a simple manner, how to get the screenshot's grid working.
This is the method calling based on if we want to show the target indicator or not (the CheckBox1
state tells us this):
Private Sub DataGridView1_CellPainting(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) _
Handles DataGridView1.CellPainting
If e.RowIndex < 0 OrElse e.ColumnIndex < 0 Then Exit Sub
If e.ColumnIndex <> Columns.Percent Then Exit Sub
Dim oRow As DataSet1.DataRow = _
DirectCast(DataGridView1.Rows(e.RowIndex).DataBoundItem, DataRowView).Row
e.Handled = True
Dim oColor As Drawing.Color = Color.Green
If CheckBox1.Checked AndAlso oRow.percent < _ciTarget Then oColor = Color.Red
If CheckBox1.Checked Then
Bar.PintaDegradado(oColor, e, oRow.percent, _ciTarget, Color.Orange)
Else
Bar.PintaDegradado(oColor, e, oRow.percent)
End If
End Sub
This is the bar
class code:
Public Class Bar
Public Shared Sub PintaDegradado(ByVal oColor As Drawing.Color, _
ByVal e As DataGridViewCellPaintingEventArgs)
Bar.PintaDegradado(oColor, e, -1)
End Sub
Public Shared Sub PintaDegradado(ByVal oColor As Drawing.Color, _
ByVal e As DataGridViewCellPaintingEventArgs, ByVal iPorcentaje As Integer)
Dim aCol As Drawing.Color() = {oColor}
Dim aPor As Integer() = {iPorcentaje}
If iPorcentaje = -1 Then
Dim aPorN As Integer() = {}
Bar.PintaDegradado(aCol, e, aPorN)
Else
Bar.PintaDegradado(aCol, e, aPor)
End If
End Sub
Public Shared Sub PintaDegradado(ByVal oColor As Drawing.Color, _
ByVal e As DataGridViewCellPaintingEventArgs, ByVal iPorcentaje As Integer, _
ByVal iObjetivo As Integer, ByVal oColorObjetivo As Drawing.Color)
Dim aCol As Drawing.Color() = {oColor, oColorObjetivo}
Dim aPor As Integer() = {iPorcentaje, iObjetivo}
Bar.PintaDegradado(aCol, e, aPor)
End Sub
Private Shared Sub PintaDegradado(ByVal aColores As Drawing.Color(), _
ByVal e As DataGridViewCellPaintingEventArgs, ByVal aPorcentajes As Integer())
Dim oPin1 As Drawing2D.LinearGradientBrush = Nothing
Dim oPin2 As Drawing2D.LinearGradientBrush = Nothing
Dim oPinO As Drawing2D.LinearGradientBrush = Nothing
Dim oColor As Drawing.Color = aColores(0)
Try
Dim oCelda As New Rectangle(e.CellBounds.X - 1, e.CellBounds.Y - 1, _
e.CellBounds.Width, e.CellBounds.Height)
For iC As Integer = 0 To aPorcentajes.Length - 1
If aPorcentajes(iC) > 100 Then aPorcentajes(iC) = 100
Next
Dim oRect1 As Rectangle
Dim oRect2 As Rectangle
Dim oObj As Rectangle
Dim oFond As Rectangle
Dim oCuad As Rectangle = Nothing
Dim iPorcentaje As Integer = 0
Dim bPor As Boolean = False
If aPorcentajes.Length > 0 Then
bPor = True
iPorcentaje = aPorcentajes(0)
If iPorcentaje > 0 Then
oRect1 = New Rectangle(oCelda.X + 4, oCelda.Y + 4, _
Math.Round(((oCelda.Width - 7) * iPorcentaje * 0.01) + 0.49),_
Math.Round((oCelda.Height - 8) / 2))
If oRect1.Width > oCelda.Width - 7 _
Then oRect1.Width = oCelda.Width - 7
oRect2 = New Rectangle(oCelda.X + 4, oRect1.Bottom - 1, _
oRect1.Width, (oCelda.Height - 6) - oRect1.Height)
oFond = New Rectangle(oCelda.X + 4, oCelda.Y + 4, _
oCelda.Width - 7, oCelda.Height - 7)
oPin1 = New Drawing2D.LinearGradientBrush(oRect1, _
Color.White, Color.FromArgb(180, oColor), _
Drawing2D.LinearGradientMode.Vertical)
oPin2 = New Drawing2D.LinearGradientBrush(oRect2, _
oColor, Color.FromArgb(70, oColor), _
Drawing2D.LinearGradientMode.Vertical)
End If
If aPorcentajes.Length > 1 Then
Dim iObj As Integer = aPorcentajes(1)
Dim iPos As Integer = oCelda.X + 4 + Math.Round_
(((oCelda.Width - 7) * iObj * 0.01) + 0.49)
Dim iIni As Integer = iPos - 20
If iIni < oCelda.X + 4 Then iIni = oCelda.X + 4
oObj = New Rectangle(iIni, oCelda.Y + 2, iPos - iIni, _
oCelda.Height - 4)
oPinO = New Drawing2D.LinearGradientBrush(oObj, _
Drawing.Color.FromArgb(0, aColores(1)), aColores(1), _
Drawing2D.LinearGradientMode.Horizontal)
End If
oCuad = New Rectangle(oCelda.X + 3, oCelda.Y + 3, oCelda.Width - 6, _
oCelda.Height - 6)
Else
oRect1 = New Rectangle(oCelda.X + 1, oCelda.Y + 1, _
oCelda.Width - 1, Math.Round(oCelda.Height / 2))
oRect2 = New Rectangle(oCelda.X + 1, oRect1.Bottom - 1, _
oCelda.Width - 1, oCelda.Height - oRect1.Height)
oFond = New Rectangle(oCelda.X + 1, oCelda.Y + 1, _
oCelda.Width - 1, oCelda.Height)
oPin1 = New Drawing2D.LinearGradientBrush(oRect1, _
Color.White, Color.FromArgb(180, oColor), _
Drawing2D.LinearGradientMode.Vertical)
oPin2 = New Drawing2D.LinearGradientBrush(oRect2, _
oColor, Color.FromArgb(70, oColor), _
Drawing2D.LinearGradientMode.Vertical)
End If
e.PaintBackground(e.CellBounds, True)
If bPor Then
e.Graphics.DrawRectangle(Pens.DimGray, oCuad)
End If
If oPin1 IsNot Nothing Then
e.Graphics.FillRectangle(Brushes.White, oFond)
e.Graphics.FillRectangle(oPin1, oRect1)
e.Graphics.FillRectangle(oPin2, oRect2)
End If
If oPinO IsNot Nothing Then
e.Graphics.FillRectangle(oPinO, oObj)
End If
e.PaintContent(oCelda)
e.Paint(oCelda, DataGridViewPaintParts.Border)
e.Handled = True
Catch ex As Exception
Debug.Print(ex.Message)
Finally
If oPin1 IsNot Nothing Then
oPin1.Dispose()
oPin1 = Nothing
End If
If oPin2 IsNot Nothing Then
oPin2.Dispose()
oPin2 = Nothing
End If
If oPinO IsNot Nothing Then
oPinO.Dispose()
oPinO = Nothing
End If
End Try
End Sub
End Class
Points of Interest
This code shows how to draw a glass effect bar: two gradient rectangles do the job. It also shows how to handle the DataGridView
's cell painting manipulation. The bars are dynamically painted, so real time data updates are shown at real time. This allows to show real time progress bars too.
History
- 4th June, 2010: Original version
- 24th August, 2010: Article updated