Kae Travis

PowerShell Combobox using a Custom DrawMode

Other Posts in this Series:


This post provides an example of creating a pretty PowerShell combobox using a custom DrawMode. Instead of using the default fonts and colours, we can override this setting to conditionally highlight combobox entries in different colours, and even use an alternating background colour.

$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(450, 180)	
$form.StartPosition = "CenterScreen"
 
$combobox = New-Object System.Windows.Forms.ComboBox
$combobox.Location = New-Object System.Drawing.Point(20, 50)
$combobox.Size = New-Object System.Drawing.Size(390, 20)	
$combobox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList;
$combobox.FlatStyle = "Flat"
$combobox.BackColor = 'White'
$combobox.Font = "Arial,8pt,style=Bold"
$combobox.Cursor = [System.Windows.Forms.Cursors]::Hand

$combobox.Add_SelectedIndexChanged({
	write-host $combobox.Text $combobox.SelectedValue
})

#must set this to override the draw mode!
$combobox.DrawMode = [System.Windows.Forms.DrawMode]::OwnerDrawFixed

$combobox.Add_DrawItem({
    
 param(
    [System.Object] $sender, 
    [System.Windows.Forms.DrawItemEventArgs] $e
    )
    
    If ($Sender.Items.Count -eq 0) {return}
    
    Try {

        #get current item
        $lbItem=$Sender.Items[$e.Index]
 
        #calculate text colour conditionally
        If ($lbItem -eq "Sample1") {
            $textColor = [System.Drawing.Color]::Red
        }
        ElseIf ($lbItem -eq "Sample2") {
            $textColor = [System.Drawing.Color]::Orange
        }
        ElseIf ($lbItem -eq "Sample3") {
            $textColor = [System.Drawing.Color]::Green
        }
        ElseIf ($lbItem -eq "Sample4") {
            $textColor = [System.Drawing.Color]::Blue
        }
        ElseIf ($lbItem -eq "Sample5") {
            $textColor = [System.Drawing.Color]::Blue
        }
        Else {
            $textColor = [System.Drawing.Color]::Black
        }


        #now calculate background color

        $backgroundColor = if(($e.State -band [System.Windows.Forms.DrawItemState]::Selected) -eq [System.Windows.Forms.DrawItemState]::Selected){ 
             #if item is in focus fill with whitesmoke
             [System.Drawing.Color]::WhiteSmoke
        }else{
            #if item not in focus

            #if we want static background color for all rows
            #[System.Drawing.Color]::White

            #or if we want alternating row colors etc

            if($e.Index % 2 -eq 0){
                [System.Drawing.Color]::White
            }else{
                [System.Drawing.Color]::AntiqueWhite
            }
        }

        #create brushes
        $BackgroundColorBrush = New-Object System.Drawing.SolidBrush($backgroundColor)            
        $TextColourBrush = New-Object System.Drawing.SolidBrush($textColor)
        
        #nice smooth rendering of fonts
        $e.Graphics.TextRenderingHint = 'AntiAlias'
        
        #default font
        $font = $e.Font
        
        #or specify a custom font
        #$font = [System.Drawing.Font]::new($e.Font.FontFamily.Name, 18)
              
        # Draw the background
        $e.Graphics.FillRectangle($BackgroundColorBrush, $e.Bounds)
        
        # Draw the text
        $e.Graphics.DrawString($lbItem, $font, $TextColourBrush, (new-object System.Drawing.PointF($e.Bounds.X, $e.Bounds.Y)))
       
        #we decide not to draw the dotted focus triangle
        #$e.DrawFocusRectangle()
    }
    Catch {
        write-host $_.Exception
    }
    Finally {
        $TextColourBrush.Dispose()
         $BackgroundColorBrush.Dispose()
    }


})

$combobox.items.Add("Sample1") | Out-Null
$combobox.items.Add("Sample2") | Out-Null
$combobox.items.Add("Sample3") | Out-Null
$combobox.items.Add("Sample4") | Out-Null
$combobox.items.Add("Sample5") | Out-Null

$form.Controls.Add($combobox)

[void]$form.showdialog()
PowerShell Combobox using a Custom DrawMode
PowerShell Combobox using a Custom DrawMode

2 thoughts on “PowerShell Combobox using a Custom DrawMode

  1. FINALLY!

    I have been searching high and low on how to customize the colors and theme of the winforms DropDownList ComboBox. I’ve poured through countless Stack Overflow posts and various forums and nothing really worked.

    The key was:
    $e.Graphics.FillRectangle($BackgroundColorBrush, $e.Bounds)

    And omitting:
    $e.DrawBackground()

    Thank you so much for this post.

    I have one last question.

    When I first launch the application, the selected item (index 0) has the “WhiteSmoke” background. And also, after I choose an item from my ComboBox and the list collapses again, the “WhiteSmoke” background color remains.

    Is there any way to revert back to a white background color once an item is chosen? Is there a way to set a default color (white) as a background when the application first launches?

    I made a short screen recording to demonstrate what I mean:
    https://streamable.com/eh16cs

    Thanks again for the great write up and code.

  2. Hi. You probably want to check the state of the combobox. Maybe replace line 58 with:

    $backgroundColor = if(
    (($e.State -band [System.Windows.Forms.DrawItemState]::Selected) -eq [System.Windows.Forms.DrawItemState]::Selected) -and
    (($e.State -band [System.Windows.Forms.DrawItemState]::Focus) -eq [System.Windows.Forms.DrawItemState]::Focus) -and
    (!(($e.State -band [System.Windows.Forms.DrawItemState]::ComboBoxEdit) -eq [System.Windows.Forms.DrawItemState]::ComboBoxEdit))
    ){

Leave a Reply