PC Review


Reply
Thread Tools Rate Thread

Changing color in Datagrid Cell - My solution

 
 
Zanna
Guest
Posts: n/a
 
      6th Mar 2004
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



--------------------------------------------------------

--
Math Parser : http://www.neodatatype.net




 
Reply With Quote
 
 
 
 
Zanna
Guest
Posts: n/a
 
      6th Mar 2004
"Zanna" <(E-Mail Removed)> wrote in message
news:7Fp2c.7125$(E-Mail Removed)...



> Public Class DataGridExtender
>
> Private blnCEditActive As Boolean
> Private objCTextBox As TextBox


Ok, the TextBox does nothing

It was a test-object: in the same way you paint a cell you can overlaps
objects adding them to the DataGrid.Controls and inflating the Rectangle by
1pixel for side (Rectange.Inflate(1,1)).

The rectangle have to be inflated *before* to assigning it to
Control.Bounds.

That's all

--
Math Parser : http://www.neodatatype.net


 
Reply With Quote
 
Jasmine
Guest
Posts: n/a
 
      8th Mar 2004
Thank You SOOO Much Zanna!!!!
Your code works very well and it was very easy to
understand!!!!


>-----Original Message-----
>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
>
>
>
>--------------------------------------------------------
>
>--
>Math Parser : http://www.neodatatype.net
>
>
>
>
>.
>

 
Reply With Quote
 
Zanna
Guest
Posts: n/a
 
      8th Mar 2004
Jasmine wrote:
> Thank You SOOO Much Zanna!!!!
> Your code works very well and it was very easy to
> understand!!!!


Happy to be of some help

After this post I changed the code a little because it has a bug when
you scroll the grid horizontally.

You need yo trap also the HScrollBar_ValueChanged and the
DataGrid_CurrentCellChanged.

Also you need to change the PaintRows routine as this:

You will see I changed the RowColor to CellFormat that is simply

Private Structure CellFormat
Public Back As Color
Public Fore As Color
Public Sub New(ByVal backColor As Color, ByVal foreColor As
Color)
Back = backColor
Fore = foreColor
End Sub
End Structure


You'll need to change it into the SetRowBackColor sub (maybe you'll want
to rename it to SetRowColors)


Private Sub PaintRows()
If (Not MyBase.DataTable Is Nothing) AndAlso _
(objCRowColors.Count > 0) AndAlso _
(MyBase.DataTable.Rows.Count > 0) Then

Dim intLFirstRowIdx As Int32 = Me.FirstVisibleRow
Dim intLFirstColIdx As Int32 = Me.FirstVisibleColumn

Dim cw As Int32
Dim cf As CellFormat
Dim clip_rect As Rectangle

clip_rect = New Rectangle(intCRowHeaderWidth + 2, _
1, _
objCGrid.ClientSize.Width -
intCRowHeaderWidth - objCVScrollBar.Width - 2, _
objCGrid.ClientSize.Height)

Dim g As Drawing.Graphics = objCGrid.CreateGraphics
g.Clip = New Region(clip_rect)

For i As Int32 = intLFirstRowIdx To intLFirstRowIdx +
objCGrid.VisibleRowCount - 1
If objCRowColors.Contains(i) Then

Dim render_rect As Rectangle

For col As Int32 = intLFirstColIdx To
intLFirstColIdx + objCGrid.VisibleColumnCount - 1
render_rect = objCGrid.GetCellBounds(i,
col)

cf = DirectCast(objCRowColors.Item(i),
CellFormat)

g.FillRectangle(New
SolidBrush(cf.Back), render_rect)


g.DrawString(MyBase.DataTable.Rows(i).Item(col).ToString, _
objCGrid.Font, _
New SolidBrush(cf.Fore), _
New
RectangleF(render_rect.X + 2, _

render_rect.Y + 2, _

render_rect.Width - 4, _

render_rect.Height - 4))

Next
End If
Next
End If
End Sub

Public ReadOnly Property FirstVisibleRow() As Int32
Get
Return
DirectCast(objCGrid.GetType.GetField("m_irowVisibleFirst", _

Reflection.BindingFlags.NonPublic Or _
Reflection.BindingFlags.GetField
Or _

Reflection.BindingFlags.Instance)
).GetValue(objCGrid), _
Int32)
End Get
End Property

Public ReadOnly Property FirstVisibleColumn() As Int32
Get
Return objCGrid.FirstVisibleColumn
End Get
End Property

 
Reply With Quote
 
Zanna
Guest
Posts: n/a
 
      8th Mar 2004
Zanna wrote:

> After this post I changed the code a little because it has a bug when
> you scroll the grid horizontally.


Oh, the intCRowHeaderWidth is (I think) always 20, but you can get it
via reflection asking for "m_kcxDefaultRowHdrWidth" that is a
BindingFlags.Static and not BindingBlag.Instance.

See youuu




 
Reply With Quote
 
Jasmine
Guest
Posts: n/a
 
      8th Mar 2004
You're my lifesaver, Zanna!!
I've noticed about the horizontal scrollbar and was trying
to figure it out myself. And then you post the new code
just right on time!! Thank you for your rapid response!!!
THANK YOU THANK YOU THANK YOU!!!


>-----Original Message-----
>Zanna wrote:
>
>> After this post I changed the code a little because it

has a bug when
>> you scroll the grid horizontally.

>
>Oh, the intCRowHeaderWidth is (I think) always 20, but

you can get it
>via reflection asking for "m_kcxDefaultRowHdrWidth" that

is a
>BindingFlags.Static and not BindingBlag.Instance.
>
>See youuu
>
>
>
>
>.
>

 
Reply With Quote
 
Jasmine
Guest
Posts: n/a
 
      9th Mar 2004
Hi Zanna,

Sorry It's me Jasmine again!
After testing out your code, there's an error that I
couldn't fix. My code always stopped at this line for some
reason:
cf = DirectCast(objCRowColors.Item(i), CellFormat)

The problem might be the CellFormat structure. I have
never used a structure before. Where should I place the
strucure??

Once again, Thank you so much!!

Jasmine

>-----Original Message-----
>Zanna wrote:
>
>> After this post I changed the code a little because it

has a bug when
>> you scroll the grid horizontally.

>
>Oh, the intCRowHeaderWidth is (I think) always 20, but

you can get it
>via reflection asking for "m_kcxDefaultRowHdrWidth" that

is a
>BindingFlags.Static and not BindingBlag.Instance.
>
>See youuu
>
>
>
>
>.
>

 
Reply With Quote
 
Zanna
Guest
Posts: n/a
 
      9th Mar 2004
Jasmine wrote:
> Hi Zanna,
>
> Sorry It's me Jasmine again!
> After testing out your code, there's an error that I
> couldn't fix. My code always stopped at this line for some
> reason:
> cf = DirectCast(objCRowColors.Item(i), CellFormat)
>
> The problem might be the CellFormat structure.


Yes, this is a structure where I store fore/back colors:

I changed its name to a more understandable

Private Structure CellColorInfo
Public Back As Color
Public Fore As Color
Public Sub New(ByVal backColor As Color, ByVal foreColor As
Color)
Back = backColor
Fore = foreColor
End Sub
End Structure

Also, for the previous "m_kcxDefaultRowHdrWidth" tips, if you use it be
sure you use "v_cxDefaultRowHdrWidth" for ARM processors (or do a try
catch on v_cxDefaultRowHdrWidth and in the catch section retry with
m_kcxDefaultRowHdrWidth)

Bye

 
Reply With Quote
 
Jasmine
Guest
Posts: n/a
 
      9th Mar 2004
Thanks Zanna!!! I got everything figured it out!!

>-----Original Message-----
>Jasmine wrote:
>> Hi Zanna,
>>
>> Sorry It's me Jasmine again!
>> After testing out your code, there's an error that I
>> couldn't fix. My code always stopped at this line for

some
>> reason:
>> cf = DirectCast(objCRowColors.Item(i), CellFormat)
>>
>> The problem might be the CellFormat structure.

>
>Yes, this is a structure where I store fore/back colors:
>
>I changed its name to a more understandable
>
> Private Structure CellColorInfo
> Public Back As Color
> Public Fore As Color
> Public Sub New(ByVal backColor As Color,

ByVal foreColor As
>Color)
> Back = backColor
> Fore = foreColor
> End Sub
> End Structure
>
>Also, for the previous "m_kcxDefaultRowHdrWidth" tips, if

you use it be
>sure you use "v_cxDefaultRowHdrWidth" for ARM processors

(or do a try
>catch on v_cxDefaultRowHdrWidth and in the catch section

retry with
>m_kcxDefaultRowHdrWidth)
>
>Bye
>
>.
>

 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Changing cell color in datagrid kanepart2@hotmail.com Microsoft VB .NET 1 1st Aug 2007 07:00 PM
changing the color of a cell in a datagrid Franck Microsoft ASP .NET 7 12th Oct 2005 07:53 AM
changing bg color of individual datagrid cell Mad Scientist Jr Microsoft VB .NET 3 23rd Nov 2004 10:37 PM
Changing color in Datagrid Cell jasmine Microsoft Dot NET Compact Framework 11 6th Mar 2004 07:44 PM
Datagrid: changing cell color JR Microsoft ADO .NET 2 21st Sep 2003 09:33 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 08:16 PM.