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()

Using PowerShell to Databind a Combobox with a Value and some Text

This post provides an example of using PowerShell to databind a combobox with a value and some text.

Creating a combobox in Powershell and adding an item to it is a relatively trivial task:

$combobox = New-Object System.Windows.Forms.ComboBox
$combobox.Items.add("alkane")

The text of the selected combobox can be obtained like so:

$combobox.Text

This is a combobox in its most simplistic form. The trouble is, I’m from an ASP.Net background and it’s often handy to bind a value (the hidden reference to the selected item – usually a primary key integer) AND some text (the value that the user sees in the combobox – the ‘friendly’ name). This requires a bit more leg work to implement and can be done by using a datatable, adding data to the datatable, and binding this datatable to our combobox like so:

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Windows.Forms.Application]::EnableVisualStyles()
#create a form
$form = New-Object System.Windows.Forms.Form
#create a datatable to bind to our combobox
$datatable = New-Object system.Data.DataTable
#Define Columns
$col1 = New-Object system.Data.DataColumn "Value",([string])
$col2 = New-Object system.Data.DataColumn "Text",([string])
#add columns to datatable
$datatable.columns.add($col1)
$datatable.columns.add($col2)
#Create a row
$datarow1 = $datatable.NewRow()
#Enter data in the row
$datarow1.Value = "Example Value 1"
$datarow1.Text = "Example Text 1"
#Add the row to the datatable
$datatable.Rows.Add($datarow1)
#Create another row
$datarow2 = $datatable.NewRow()
#Enter data in the row
$datarow2.Value = "Example Value 2"
$datarow2.Text = "Example Text 2"
#Add the row to the datatable
$datatable.Rows.Add($datarow2)
#create a combobox
$combobox = New-Object System.Windows.Forms.ComboBox		
$combobox.Add_SelectedIndexChanged({
#output the selected value and text
write-host $combobox.SelectedItem["Value"] $combobox.SelectedItem["Text"]
})
#clear combo before we bind it
$combobox.Items.Clear()
#bind combobox to datatable
$combobox.ValueMember = "Value"
$combobox.DisplayMember = "Text"
$combobox.Datasource = $datatable
#add combobox to form
$form.Controls.Add($combobox)	
#show form
[void]$form.showdialog()