Custom DataGridView cell definition

I have built an extended version of the DataGridView control which is used in an unbound mode and I want to have a custom cell definition for a portion of the matrix. Each custom cell can hold only two characters and each character can have a different backgound color. For example, a cell could have a green space (which would look like a green block, and an "X" with a red background. The colors and characters can change independently. I presume I create a class that inherits "cell" but beyond that it gets a bit fuzzy.
Who is Participating?
lojkConnect With a Mentor .Net and Infrastructure ConsultantCommented:
THis was a nightmare in .net1.x but the datgridview makes it sooo easy...
Just handle the paint event for the cell and draw on what you want...

    Private Sub grd_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles grdScheduler.CellPainting, grdModifications.CellPainting
        If e.ColumnIndex = 3 And e.RowIndex >= 0 Then 'Paint The Words on the Status Field
            Dim displayvalue As String = ""
            Select Case UCase(CheckNullString(e.Value)).Substring(0, 1)
                Case "H"
                    displayvalue = "Hold"
                Case "N"
                    displayvalue = "Not Yet Started"
                Case "S"
                    displayvalue = "Succesful"
                Case "Y"
                    displayvalue = "Running"
                Case "F"
                    displayvalue = "Failed"
                Case Else
                    displayvalue = e.Value
            End Select

            DataGridViewDrawCellText(CType(sender, DataGridView), e, displayvalue)
            e.Handled = True
        End If

    End Sub

Public Shared Sub DataGridViewDrawCellText(ByRef objCurrentDataGridView As DataGridView, ByRef objDataGridViewCellPaintingEventArgs As DataGridViewCellPaintingEventArgs, ByVal TextToDraw As String)

        Dim newRect As New Rectangle(objDataGridViewCellPaintingEventArgs.CellBounds.X + 1, objDataGridViewCellPaintingEventArgs.CellBounds.Y + 1, _
                               objDataGridViewCellPaintingEventArgs.CellBounds.Width - 4, objDataGridViewCellPaintingEventArgs.CellBounds.Height - 4)
        Dim backColorBrush As New SolidBrush(objDataGridViewCellPaintingEventArgs.CellStyle.BackColor)
        Dim gridBrush As New SolidBrush(objCurrentDataGridView.GridColor)
        Dim gridLinePen As New Pen(gridBrush)


            ' Erase the cell.
            objDataGridViewCellPaintingEventArgs.Graphics.FillRectangle(backColorBrush, objDataGridViewCellPaintingEventArgs.CellBounds)

            ' Draw the grid lines (only the right and bottom lines;
            ' DataGridView takes care of the others).
            objDataGridViewCellPaintingEventArgs.Graphics.DrawLine(gridLinePen, objDataGridViewCellPaintingEventArgs.CellBounds.Left, _
                objDataGridViewCellPaintingEventArgs.CellBounds.Bottom - 1, objDataGridViewCellPaintingEventArgs.CellBounds.Right - 1, _
                objDataGridViewCellPaintingEventArgs.CellBounds.Bottom - 1)
            objDataGridViewCellPaintingEventArgs.Graphics.DrawLine(gridLinePen, objDataGridViewCellPaintingEventArgs.CellBounds.Right - 1, _
                objDataGridViewCellPaintingEventArgs.CellBounds.Top, objDataGridViewCellPaintingEventArgs.CellBounds.Right - 1, _

            ' Draw the inset highlight box.
            '  objDataGridViewCellPaintingEventArgs.Graphics.DrawRectangle(Pens.Blue, newRect)

            ' Draw the text content of the cell, ignoring alignment.
            If Not (objDataGridViewCellPaintingEventArgs.Value Is Nothing) Then

                objDataGridViewCellPaintingEventArgs.Graphics.DrawString(TextToDraw, objDataGridViewCellPaintingEventArgs.CellStyle.Font, _
                Brushes.Black, objDataGridViewCellPaintingEventArgs.CellBounds.X + 2, objDataGridViewCellPaintingEventArgs.CellBounds.Y + 2, _
            End If
            objDataGridViewCellPaintingEventArgs.Handled = True

        End Try
    End Sub

In this example i just paint the word 'Hold' where the cell contains 'H' but you could easily change this for your purposes...

lojk.Net and Infrastructure ConsultantCommented:
kudos to the original sample i built that up from, cant remember where it was now...
tmostadAuthor Commented:
I think this example is pretty close but not close enough to answer my main question which is how do I change the background color at the character level. This shows painting the cell background color which I know how to do but cannot find a property to set the background color of a character. Perhaps I don't understand the example well enough and someone needs to simply point out what I am missing. Thanks.
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

tmostadAuthor Commented:
I reread my original questions and I didn't articulate the the green block and the X with the red background are in the same cell. Maybe this makes the question clearer?
lojk.Net and Infrastructure ConsultantCommented:
you just need to paint what you need onto the cell - you have the cell bounds and you need a brush and...

Im not sure what you mean by 'background color at the character level'. To me that is just the layer of pixels drawn before the text is drawn on top- you just need to draw 2 coloured boxes then drawtext the text on top..

If this doesnt solve it you are going to need to implement a new columndisplaytype with  a couple of labels in whose backcolors can be set(although i suspect in that you may end up painting the characters individually), check out your MSDN (DataGridView) for some pretty thorough if not intuitive examples on this...

How to: Host Controls in Windows Forms DataGridView Cells
tmostadAuthor Commented:
I don't know how long you have been at this but I have been around a long time and my early experience dates back to the day when you programmed the CRT controller directly and characters could have background color as well as blink, underline, etc. attributes. This model was nice for doing control console work since it was simple to highlight abnormal status and such although it was not good at all for doing detailed graphics. Of course Windows is raster based and excellent for graphics. I am trying to add in character-based attributes for my app and this is what I am referring to.  I can see how it might be done by creating Font objects and then changing the attributes of the fonts. I was hoping to find some examples to accelerate my learning but the approach you suggest could also work though differently than I had first imagined.
lojk.Net and Infrastructure ConsultantCommented:
Im 30 now and learned basic on my Zx Spectrum around '84 and yes i do remember the framebuffer starting at 16384(h4000) for however many (4096 was it?) bytes and then 768 bytes of Color-Code Nybble Pair Bytes for Fore and BackColor. Ah those were the *good* days, when programming assembler was still, well , possible, and computers were still uncool in a superbly retro cool way ;-)

(un)fortunately things have moved on and painting a couple of squares in your desired colours then Drawing the text on will almost certainly be the easiest and quickest way to do this. Like i said you can go down the CustomDataGridViewColumn route if you want but i promise you will regret it if you want this doing quickly (you can always come back later and refactor if you really dont like the paint method).

The only other alternative i can offer you is to

Create A usercontrol to Represent your row, containing labels and textboxes etc
Create a usercontrol to represent a collection of the above row controls
Create all code to make these controls display what you need from a dataset

and manage all of the display and rendering yourself.... *shudders*... I did a very similar thing in VB6 (more than) once, it was (usually) a disaster...

Pre.Net Painting directly to the screen or components was considered fairly hardcore and it is for the reason that it has been made more accessible and thats why we are discussing it as a serious option. Change isnt always bad: Amongst others, GridCell Painting, Object Serialisation (see current Q_21885251), XML (Generally) and in fact the whole .NET concept has changed my coding style in so many good ways (If I squint I can just about see my ZXSpectrum, way, way off in the distance) that im willing to live with a few days of frustation in exchange..
tmostadAuthor Commented:
Thanks for your help. As I think about it more your first answer has begun to make perfect sense. I will include cell attributes which will be characters which will never be confused as cell content. I will strip them off and draw the cell colors based on them then draw the text on top of them.

I am 46 and feeling like an old dog learning a new trick - having fun but synapses don't seem to rewire as quickly they once did. I cut my teeth in the computer biz switching in (via front panel toggle switches) the paper tape bootloader for an Intel 4004 (the 4-bit predecessor to the 8008 which preceeded the 8080). The process sure kept the software light and lean...!
lojk.Net and Infrastructure ConsultantCommented:
Its resisting the changes that makes them more difficult to accept.

You are from before *even my time*...

tmostadAuthor Commented:
BTW - This works beautifully. Thanks for your help.
lojk.Net and Infrastructure ConsultantCommented:
Glad to hear it. If you're happy, I'm happy... ;-)

For reference to anybody else trying to achieve the same thing, I'm sure that tmostad will agree with me that it is not as complicated as you think it is, or as it looks and the results can be truly excellent. This is a very basic example but there is almost no limit - Ive seen some great examples for gradient filling cells, painting images and custom progress bars to name but a few.

Another handy tip for this scenario(i.e the next problem on from this) is instead of configuring, for example, drop down controls or checkboxes in columns i  set the columns to readonly and create Context Menu Strips bound to that column. This allows you to present to the user a method of changing the values without affecting the existing painted cell during edit time and these context menu strips can be as complicated as you need (and be setup at load or even popup time)... Catch the Grid_ContextMenuRequested event to make a reference to the current cell about to be edited then on the contextmenu_click set that cell item value to the required value.. Luvvly Jubbly!

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.