Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Gain Access To DataGridView Canned Controls

4.50/5 (14 votes)
5 Oct 20063 min read 1   2K  
How to gain access to the DataGridViewComboBoxEditingControl’s properties, methods, and events.

Sample Image - maximum width is 600 pixels

Introduction

Why reinvent the wheel when you can just get new hub caps? In this article, I will show how to gain access to the DataGridViewComboBoxEditing control’s properties, methods, and events. Other examples I’ve seen show how to implement custom controls, but I didn’t want to create my own DropDownList control. What I needed was to change the DisplayStyle to DropDownButton, alternate the BackColor of the list, and set the ForeColor to red if the list item begins with EXPIRED.

Using the code

The first item is a no brainer, the DisplayStyle is one of the few properties exposed by the DataGridViewComboBoxColumn. The other two, however, have no properties, methods, or events exposed that can allow these changes. With the ComboBox control, you could use the DrawItem event, or override the OnDrawItem method to accomplish this. But the DataGridViewComboBoxColumn does not expose the ComboBox, in fact it is obscured by three classes. The DataGridViewComboBoxColumn contains a DataGridViewComboBoxCell object which contains a DataGridViewComboBoxEditingControl object which inherits from the ComboBox class. Urggggg!

Sample Image - maximum width is 600 pixels

When I first realized these successions, I nearly gave up on the idea, but then I thought just maybe I could use inheritance to gain access to the ComboBox. This would be tricky, and the DataGridViewComboBoxColumn and DataGridViewComboBoxCell would have to allow alternate object types to be used.

I created three classes, DropDownListColumn which inherits DataGridViewComboBoxColumn, DropDownListCell which inherits DataGridViewComboBoxCell, and DropDownListEditingControl which inherits DataGridViewComboBoxEditingControl which inherits ComboBox.

Sample Image - maximum width is 600 pixels

The DataGridViewComboBoxColumn exposes the CellTemplate property which gets or sets the object used in the DataGridView cells. This property is changed in the default constructor within my new class, DropDownListColumn.

VB.NET
Public Class DropDownListColumn
   Inherits DataGridViewComboBoxColumn
   Public Sub New()
   'Set the type used in the DataGridView
      Me.CellTemplate = New DropDownListCell
   End Sub
End Class

The DataGridViewComboBoxCell’s EditType property returns the type of editing control used by the cell to edit the value. I override this property in my new class, DropDownListCell, and return the type DropDownListEditingControl. There is also the GetFormattedValue function which allows the ForeColor of the text in the cell to be altered. The ForeColor needs to be altered in the drop down list as well.

VB.NET
Public Class DropDownListCell
    Inherits DataGridViewComboBoxCell

    Public Overrides ReadOnly Property EditType() As Type
        Get
            ' Return the type of the editing contol that 
            ' the DropDownListCell uses.
            Return GetType(DropDownListEditingControl)
        End Get
    End Property

    Protected Overrides Function GetFormattedValue( _
        ByVal value As Object, ByVal rowIndex As Integer, _
        ByRef cellStyle As System.Windows.Forms.DataGridViewCellStyle, _
        ByVal valueTypeConverter As System.ComponentModel.TypeConverter, _
        ByVal formattedValueTypeConverter As _
              System.ComponentModel.TypeConverter, _
        ByVal context As _
              System.Windows.Forms.DataGridViewDataErrorContexts) As Object

        'Get object that is diplayed in the DataGridView cells 
        'with default formatting
        Dim obj As Object = MyBase.GetFormattedValue( _
                value, rowIndex, cellStyle, _
                valueTypeConverter, formattedValueTypeConverter, _
                context)

        'If the text is prefixed with EXPIRED then make the font red
        If Not IsNothing(obj) AndAlso obj.ToString.StartsWith("EXPIRED") Then
            cellStyle.ForeColor = System.Drawing.Color.Red
        End If

        Return obj
    End Function
End Class

The DataGridViewComboBoxEditingControl is the final class we need to inherit from. First, we need to override the default constructor to set a couple of properties. We need to set DrawMode to OwnerDrawFixed. This causes the DrawItem event to fire, allowing the developer to change the appearance of the list at runtime. We also need to set DropDownStyle to DropDownList, making the ComboBox a DropDownList. I could leave this property alone and set it in the properties page for the DropDownListColumn, but I would have to do this each time I use the control.

To change the BackColor and the ForeColor, we need to override OnDrawItem. Within the subroutine, we can use the System.Windows.Forms.DrawItemEventArgs to render the FillRectangle in either SystemColors.Window or SystemColors.ControlLight, two of my favorite colors. We can then look at the ToString method of the list item object to see if it is prefixed with EXPIRED. If it is, use a Color.Red SolidBrush, otherwise use a SystemColors.ControlText SolidBrush to render the text. The ToString method may need to be overridden in the list item's object class, or you may need to select another property to examine.

VB
Public Class DropDownListEditingControl
    Inherits DataGridViewComboBoxEditingControl

    Public Sub New()
        MyBase.New()
        'This will cause the DrawItem event to raise,
        'allowing changes to be made to the appearance
        'at run time
        Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed

        'Make this a DropDownList 
        Me.DropDownStyle = ComboBoxStyle.DropDownList
    End Sub

    Protected Overrides Sub OnDrawItem( _
        ByVal e As System.Windows.Forms.DrawItemEventArgs)

        ' Create a rectagle the size of the item container
        Dim rec As New Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, _
                                 e.Bounds.Height)

        If Me.Enabled Then
            'If the item is being pointed to highlight it
            If (e.State And DrawItemState.Focus) = DrawItemState.Focus Then
                e.Graphics.FillRectangle( _
                New SolidBrush(System.Drawing.SystemColors.Highlight), rec)
            
            'The next two clauses will cause the item backcolor to alternate
            ElseIf (e.State And DrawItemState.ComboBoxEdit) = _
                   DrawItemState.ComboBoxEdit _
                   OrElse e.Index Mod 2 = 1 Then
                e.Graphics.FillRectangle( _
                New SolidBrush(System.Drawing.SystemColors.Window), rec)
            Else
                e.Graphics.FillRectangle( _
                New SolidBrush(System.Drawing.SystemColors.ControlLight), rec)
            End If
        Else
            'Grey out the box it is disablbed
            e.Graphics.FillRectangle( _
            New SolidBrush(System.Drawing.SystemColors.Control), rec)
        End If

        'If there is an item
        If e.Index > -1 Then
            Dim obj As Object = Me.Items(e.Index)
            'If the item is selected highlight it            
            If (e.State And DrawItemState.Focus) = DrawItemState.Focus Then
                Dim HighlightedText As _
                New SolidBrush(System.Drawing.SystemColors.HighlightText)
                e.Graphics.DrawString(obj.ToString, e.Font, _
                                      HighlightedText, rec)
            'If the item starts with EXPIRED make it red
            ElseIf obj.ToString.StartsWith("EXPIRED") Then
                Dim ExpireText As New SolidBrush(System.Drawing.Color.Red)
                e.Graphics.DrawString(obj.ToString, e.Font, ExpireText, rec)
            Else
                Dim NormalText As New _
                  SolidBrush(System.Drawing.SystemColors.ControlText)
                e.Graphics.DrawString(obj.ToString, e.Font, NormalText, rec)
            End If
        Else
            Dim NormalText As New _
                 SolidBrush(System.Drawing.SystemColors.ControlText)
            e.Graphics.DrawString("", e.Font, NormalText, rec)
        End If
    End Sub
End Class

There is not a lot of code to this technique, and it could be easily applied to other canned DataGridView column controls. Additionally, this technique gains you access to many methods, properties, and events otherwise unavailable. Just think of all the hub caps one could create.

History

  • Submitted on 10/5/2006

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here