Click here to Skip to main content
15,064,166 members
Articles / Desktop Programming / Windows Forms
Article
Posted 5 Oct 2006

Stats

88.9K views
1.9K downloads
45 bookmarked

Gain Access To DataGridView Canned Controls

Rate me:
Please Sign up or sign in to vote.
4.50/5 (14 votes)
5 Oct 20063 min read
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

Share

About the Author

mark.stratman
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pin
csrss21-Dec-10 8:56
Membercsrss21-Dec-10 8:56 
QuestionDataGridViewComboBoxColumn population Pin
geetesh.12315-Oct-09 2:28
Membergeetesh.12315-Oct-09 2:28 
QuestionVariable height drawing Pin
Rachel Byford5-May-09 4:51
MemberRachel Byford5-May-09 4:51 
GeneralExcellent Article Pin
StairAmy17-Jul-07 4:50
MemberStairAmy17-Jul-07 4:50 
GeneralDataGridViewComboBoxColumn problem... Pin
Tim8w15-Mar-07 9:49
MemberTim8w15-Mar-07 9:49 
Generaldatagridview Pin
vksharma3226-Feb-07 20:38
Membervksharma3226-Feb-07 20:38 
Generalquestion regarding the order of displayed properties Pin
billy p17-Oct-06 8:48
Memberbilly p17-Oct-06 8:48 
GeneralRe: question regarding the order of displayed properties Pin
mark.stratman17-Oct-06 13:40
Membermark.stratman17-Oct-06 13:40 
GeneralRe: question regarding the order of displayed properties Pin
billy p18-Oct-06 3:16
Memberbilly p18-Oct-06 3:16 
GeneralRe: question regarding the order of displayed properties Pin
billy p18-Oct-06 4:03
Memberbilly p18-Oct-06 4:03 
Hi Mark,

I think I figured the work around to my column order issue, eventhough I would still love to know how the .Net framework decides the order in which an object's public properties get displayed in columns on the grid.

In any case, I discoverd two things. First, if you mistakenly assign the BindingList object to the DataSource property of the DataGridView - BEFORE YOU ADD THE DATAGRIDVIEW TO THE FORM - the properties of the underlying object in the BindingList will display, but the column count of the grid will be zero. Therefore you can't do a whole lot with the grid in terms of changing its appearence.

If you execute the DataSource assignment after adding the DataGridView to the form, then you can change the DisplayIndex property of each column to achieve the desired column display order. So, if I wanted the Description column of your DataGridViewDemo to display first (leftmost), I would add the following line of code:

Me.DataGridViewDemo.Columns("DescriptionDataGridViewTextBoxColumn").DisplayIndex = 0


Don't ask me why the name of your Description column is "DescriptionDataGridViewTextBoxColumn", as opposed to simply "Description". When I do not use the IDE to create BindingLists or BindingSource objects, the names of my columns exactly coincide with the names of the public properties of the object that I am displaying (Widget in your example).

Anyway, thanks again for your help, and for posting the project. It was really helpful.

Billy

QuestionGot a Need for similar tool in VS2003 Pin
curcio110-Oct-06 4:05
Membercurcio110-Oct-06 4:05 
AnswerRe: Got a Need for similar tool in VS2003 Pin
mark.stratman10-Oct-06 8:53
Membermark.stratman10-Oct-06 8:53 
GeneralBrilliant [modified] Pin
BarryGSumpter6-Oct-06 13:45
MemberBarryGSumpter6-Oct-06 13:45 
GeneralRe: Brilliant Pin
mark.stratman9-Oct-06 7:13
Membermark.stratman9-Oct-06 7:13 
GeneralRe: Brilliant Pin
BarryGSumpter9-Oct-06 12:22
MemberBarryGSumpter9-Oct-06 12:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.