Z
Zanna
Hi!
I hope jasmine can read this because she had my identical problem.
I solved it in this way and it seems to work fine, even if the re-painting
is "not-so-fast"
What do you need
- Obtain the VScrollBar for calculating the effective DataGrid client area.
- Trap the Scroll event: datagrid does not provide it, but the VScrollBar
do.
- Define a list of color/rows to color
- Do a row-painting each time
- the DataGrid scrolls
- the DataGrid paints (i.e.: the column size is changed by the user)
- a new back color is defined
Here is my code (sorry it is a little long).
I done a class that "extends" the DataGrid
In this code I havn't defined a ForeColor for cells, but as you could see is
really simple to improve it, maybe as a couple of Back-and-Fore colors
value.
Also this show how to color a full row: again is really simple to change it
for let it paint a single cell.
Every suggestion on this code is welcome.
-------- You can cut and paste in a new .vb file -------
Imports System.Data
Imports System
' Needed by DatagridExtender
Imports System.Windows.Forms
Imports System.Reflection
Imports System.Drawing
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Codice generato da Progettazione Windows Form "
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
MyBase.Dispose(disposing)
End Sub
Friend WithEvents DataGrid1 As System.Windows.Forms.DataGrid
Private Sub InitializeComponent()
Me.DataGrid1 = New System.Windows.Forms.DataGrid
'
'DataGrid1
'
Me.DataGrid1.Location = New System.Drawing.Point(16, 24)
Me.DataGrid1.Size = New System.Drawing.Size(208, 144)
Me.DataGrid1.Text = "DataGrid1"
'
'Form1
'
Me.Controls.Add(Me.DataGrid1)
Me.Text = "Form1"
End Sub
#End Region
Dim dgx As DataGridExtender
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim t As New DataTable
dgx = New DataGridExtender(DataGrid1)
t.Columns.Add("Column1")
t.Columns.Add("Column2")
For i As Int32 = 1 To 20
t.Rows.Add(New Object() {"This is the long line #" +
i.ToString})
If i Mod 3 = 0 Then
dgx.SetRowBackColor(i, Drawing.Color.Red)
End If
Next i
DataGrid1.DataSource = t
End Sub
End Class
Public Class DataGridExtender
Private blnCEditActive As Boolean
Private objCTextBox As TextBox
Private WithEvents objCGrid As DataGrid
Private WithEvents objCVScrollBar As VScrollBar
Private objCRowBackColors As New System.Collections.Hashtable
Public Sub New(ByVal grid As DataGrid)
objCGrid = grid
objCVScrollBar = DirectCast(grid.GetType().GetField("m_sbVert",
_
BindingFlags.NonPublic Or _
BindingFlags.GetField Or _
BindingFlags.Instance).GetValue(grid), VScrollBar)
'hsb = (HScrollBar)grid.GetType().GetField("m_sbHorz",
BindingFlags.NonPublic|BindingFlags.GetField|BindingFlags.Instance).GetValue
(grid);
End Sub
Public Sub SetRowBackColor(ByVal rowIndex As Int32, ByVal
rowBackColor As Drawing.Color)
If objCRowBackColors.Contains(rowIndex) Then
objCRowBackColors.Remove(rowIndex)
End If
If (rowBackColor.ToArgb <> Drawing.SystemColors.Window.ToArgb)
Then
objCRowBackColors.Add(rowIndex, rowBackColor)
PaintRows()
End If
End Sub
Private Sub PaintRows()
Dim dt As DataTable = DirectCast(objCGrid.DataSource, DataTable)
If (Not objCGrid.DataSource Is Nothing) AndAlso _
(dt.Rows.Count > 0) AndAlso _
(objCRowBackColors.Count > 0) Then
Dim intLLeft As Int32 = objCGrid.GetCellBounds(0, 0).Left
Dim ht As DataGrid.HitTestInfo = objCGrid.HitTest(1,
intLLeft)
Dim cw As Int32
Dim maxw As Int32 = objCGrid.ClientSize.Width - intLLeft -
objCVScrollBar.Width
For i As Int32 = ht.Row To ht.Row + objCGrid.VisibleRowCount
If objCRowBackColors.Contains(i) Then
Dim g As Drawing.Graphics = objCGrid.CreateGraphics
Dim r As Rectangle
cw = 0
For col As Int32 = 0 To dt.Columns.Count - 1
r = objCGrid.GetCellBounds(i, col)
' this is for avoid painting over the
' scrollbox in the bottom-right
cw += r.Width
If cw > maxw Then
r.Width -= (cw - maxw)
End If
g.FillRectangle(New
SolidBrush(DirectCast(objCRowBackColors.Item(i), _
Color)), r)
g.DrawString(dt.Rows(i).Item(col).ToString, _
objCGrid.Font, _
New SolidBrush(objCGrid.ForeColor),
_
New RectangleF(r.X + 2, r.Y + 2,
r.Width, r.Height))
Next
End If
Next
End If
End Sub
Private Sub objCVScrollBar_ValueChanged(ByVal sender As Object,
ByVal e As System.EventArgs) Handles objCVScrollBar.ValueChanged
PaintRows()
End Sub
Private Sub objCGrid_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles objCGrid.Paint
PaintRows()
End Sub
End Class
I hope jasmine can read this because she had my identical problem.
I solved it in this way and it seems to work fine, even if the re-painting
is "not-so-fast"
What do you need
- Obtain the VScrollBar for calculating the effective DataGrid client area.
- Trap the Scroll event: datagrid does not provide it, but the VScrollBar
do.
- Define a list of color/rows to color
- Do a row-painting each time
- the DataGrid scrolls
- the DataGrid paints (i.e.: the column size is changed by the user)
- a new back color is defined
Here is my code (sorry it is a little long).
I done a class that "extends" the DataGrid
In this code I havn't defined a ForeColor for cells, but as you could see is
really simple to improve it, maybe as a couple of Back-and-Fore colors
value.
Also this show how to color a full row: again is really simple to change it
for let it paint a single cell.
Every suggestion on this code is welcome.
-------- You can cut and paste in a new .vb file -------
Imports System.Data
Imports System
' Needed by DatagridExtender
Imports System.Windows.Forms
Imports System.Reflection
Imports System.Drawing
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Codice generato da Progettazione Windows Form "
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
MyBase.Dispose(disposing)
End Sub
Friend WithEvents DataGrid1 As System.Windows.Forms.DataGrid
Private Sub InitializeComponent()
Me.DataGrid1 = New System.Windows.Forms.DataGrid
'
'DataGrid1
'
Me.DataGrid1.Location = New System.Drawing.Point(16, 24)
Me.DataGrid1.Size = New System.Drawing.Size(208, 144)
Me.DataGrid1.Text = "DataGrid1"
'
'Form1
'
Me.Controls.Add(Me.DataGrid1)
Me.Text = "Form1"
End Sub
#End Region
Dim dgx As DataGridExtender
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim t As New DataTable
dgx = New DataGridExtender(DataGrid1)
t.Columns.Add("Column1")
t.Columns.Add("Column2")
For i As Int32 = 1 To 20
t.Rows.Add(New Object() {"This is the long line #" +
i.ToString})
If i Mod 3 = 0 Then
dgx.SetRowBackColor(i, Drawing.Color.Red)
End If
Next i
DataGrid1.DataSource = t
End Sub
End Class
Public Class DataGridExtender
Private blnCEditActive As Boolean
Private objCTextBox As TextBox
Private WithEvents objCGrid As DataGrid
Private WithEvents objCVScrollBar As VScrollBar
Private objCRowBackColors As New System.Collections.Hashtable
Public Sub New(ByVal grid As DataGrid)
objCGrid = grid
objCVScrollBar = DirectCast(grid.GetType().GetField("m_sbVert",
_
BindingFlags.NonPublic Or _
BindingFlags.GetField Or _
BindingFlags.Instance).GetValue(grid), VScrollBar)
'hsb = (HScrollBar)grid.GetType().GetField("m_sbHorz",
BindingFlags.NonPublic|BindingFlags.GetField|BindingFlags.Instance).GetValue
(grid);
End Sub
Public Sub SetRowBackColor(ByVal rowIndex As Int32, ByVal
rowBackColor As Drawing.Color)
If objCRowBackColors.Contains(rowIndex) Then
objCRowBackColors.Remove(rowIndex)
End If
If (rowBackColor.ToArgb <> Drawing.SystemColors.Window.ToArgb)
Then
objCRowBackColors.Add(rowIndex, rowBackColor)
PaintRows()
End If
End Sub
Private Sub PaintRows()
Dim dt As DataTable = DirectCast(objCGrid.DataSource, DataTable)
If (Not objCGrid.DataSource Is Nothing) AndAlso _
(dt.Rows.Count > 0) AndAlso _
(objCRowBackColors.Count > 0) Then
Dim intLLeft As Int32 = objCGrid.GetCellBounds(0, 0).Left
Dim ht As DataGrid.HitTestInfo = objCGrid.HitTest(1,
intLLeft)
Dim cw As Int32
Dim maxw As Int32 = objCGrid.ClientSize.Width - intLLeft -
objCVScrollBar.Width
For i As Int32 = ht.Row To ht.Row + objCGrid.VisibleRowCount
If objCRowBackColors.Contains(i) Then
Dim g As Drawing.Graphics = objCGrid.CreateGraphics
Dim r As Rectangle
cw = 0
For col As Int32 = 0 To dt.Columns.Count - 1
r = objCGrid.GetCellBounds(i, col)
' this is for avoid painting over the
' scrollbox in the bottom-right
cw += r.Width
If cw > maxw Then
r.Width -= (cw - maxw)
End If
g.FillRectangle(New
SolidBrush(DirectCast(objCRowBackColors.Item(i), _
Color)), r)
g.DrawString(dt.Rows(i).Item(col).ToString, _
objCGrid.Font, _
New SolidBrush(objCGrid.ForeColor),
_
New RectangleF(r.X + 2, r.Y + 2,
r.Width, r.Height))
Next
End If
Next
End If
End Sub
Private Sub objCVScrollBar_ValueChanged(ByVal sender As Object,
ByVal e As System.EventArgs) Handles objCVScrollBar.ValueChanged
PaintRows()
End Sub
Private Sub objCGrid_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles objCGrid.Paint
PaintRows()
End Sub
End Class