In the following example, how can I highlight (change the background color) of specific items in the dropdown list? To be specific, I am talking about the items in the "dropdown list" for the DataGridViewComboBox.
I want to highlight for the user the specific item(s) that are bad choices.
Please provide a working code example in vb.net.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As New DataTable
dt.Columns.Add("id", GetType(Integer))
dt.Columns.Add("list", GetType(String))
dt.Columns.Add("goodChoice", GetType(Boolean))
dt.Rows.Add(10, "Lemon")
dt.Rows.Add(20, "Apple")
dt.Rows.Add(30, "Star Fruit", False)
dt.Rows.Add(40, "Orange")
Dim newColumn As New DataGridViewComboBoxColumn()
With newColumn
.HeaderText = "Choices"
.Name = "Choices"
.DataSource = dt
.DisplayMember = "list"
.ValueMember = "id"
End With
DataGridView1.Columns.Add(newColumn)
End Sub
Try handling the EditingControlShowing
event to subscribe to the ComboBox.DrawItem
event. In this event handler you'll grab the underlying DataTable
DataSource
. When that item's goodChoice
is False
and the item is not the focused item, fill it's background color.
Private Sub DataGridView1_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
If TypeOf e.Control Is ComboBox Then
Dim cb As ComboBox = TryCast(e.Control, ComboBox)
cb.DrawMode = DrawMode.OwnerDrawFixed
RemoveHandler cb.DrawItem, AddressOf DrawGridComboBoxItem
AddHandler cb.DrawItem, AddressOf DrawGridComboBoxItem
End If
End Sub
Private Sub DrawGridComboBoxItem(sender As Object, e As DrawItemEventArgs)
If e.Index <> -1 Then
e.DrawBackground()
Dim cb As ComboBox = TryCast(sender, ComboBox)
Dim dt As DataTable = TryCast(cb.DataSource, DataTable)
If (e.State And DrawItemState.Focus) <> DrawItemState.Focus AndAlso cb.DroppedDown Then
If dt.Rows(e.Index).Item("goodChoice") Then
e.Graphics.FillRectangle(Brushes.White, e.Bounds)
Else ' Added for follow-up question.
e.Graphics.FillRectangle(Brushes.Red, e.Bounds)
End If
End If
e.Graphics.DrawString(dt.Rows(e.Index).Item("Name"), e.Font, Brushes.Black, e.Bounds)
e.DrawFocusRectangle()
End If
End Sub
My follow-up question is, if and when the red colored item is selected, how can I make the color stick when exiting the edit mode of the control?
Set the BackColor
of the cell itself. (Note: This will also alter the dropped down items, so we add an Else
statement to the DrawGridComboBoxItem
method above.)
Set the color when the cell value changes:
Private Sub DataGridView1_ValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
If TypeOf DataGridView1.CurrentCell Is DataGridViewComboBoxCell Then
Dim cell As DataGridViewComboBoxCell = TryCast(DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex), DataGridViewComboBoxCell)
Dim dt As DataTable = TryCast(cell.DataSource, DataTable)
Dim row() As DataRow = dt.Select("ID = " & cell.Value)
cell.Style.BackColor = If(row(0).Item("goodChoice"), SystemColors.ControlLight, Color.Red)
End If
End Sub
Then use that color by manually painting the background:
Private Sub DataGridView1_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DataGridView1.CellPainting
If e.RowIndex >= 0 And e.ColumnIndex >= 0 Then
If TypeOf DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewComboBoxCell Then
Dim cell As DataGridViewComboBoxCell = DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex)
Dim color As Color = If(cell.Style.ForeColor.Name = "0", Color.Black, cell.Style.ForeColor)
Using backbrush = New SolidBrush(cell.Style.BackColor)
Using brush = New SolidBrush(color)
Using format = New StringFormat()
e.Paint(e.ClipBounds, DataGridViewPaintParts.Background)
e.Paint(e.ClipBounds, DataGridViewPaintParts.Border)
e.Paint(e.ClipBounds, DataGridViewPaintParts.ContentBackground)
e.Paint(e.ClipBounds, DataGridViewPaintParts.ErrorIcon)
e.Paint(e.ClipBounds, DataGridViewPaintParts.Focus)
e.Paint(e.ClipBounds, DataGridViewPaintParts.SelectionBackground)
format.LineAlignment = StringAlignment.Center
Dim rect = New Rectangle(e.CellBounds.X + 1, e.CellBounds.Y + 1, e.CellBounds.Width - 19, e.CellBounds.Height - 3)
e.Graphics.FillRectangle(backbrush, rect)
e.Graphics.DrawString(cell.FormattedValue, e.CellStyle.Font, brush, e.CellBounds, format)
e.Handled = True
End Using
End Using
End Using
End If
End If
End Sub