nkasco nkasco - 3 months ago 74
PowerShell Question

ListBox Alternating Shading PowerShell

I seem to be stuck trying to add a bit of style to my form. I have a ListBox and I want to add alternate shading to every other row. Is this even possible? I tried looking at the $ListBox.Items property and below that I don't see anything for background options. Any ideas?

$ListBox = New-Object System.Windows.Forms.ListBox
$ListBox.Size = '325,95'
$ListBox.Location = '345,25'
$ListBox.Items.Add("Checking...") > $null

Answer

The only way to do this in with the ListBox control in Windows Forms is by hijacking the actual drawing of each row.

First, change the DrawMode property of the ListBox:

$ListBox.DrawMode = [System.Windows.Forms.DrawMode]::OwnerDrawFixed

This will allow us to override graphic rendering of the items via the DrawItem event.

Now all we need is to define the function that will draw the items. I found this great example in C# on doing alternate row colors without affecting selected items.

Luckily, C# is easily ported to PowerShell:

$ListBox.add_DrawItem({

    param([object]$s, [System.Windows.Forms.DrawItemEventArgs]$e)

    if ($e.Index -gt -1)
    {
        Write-Host "Drawing item at index $($e.Index)"

        <# If the item is selected set the background color to SystemColors.Highlight 
         or else set the color to either WhiteSmoke or White depending if the item index is even or odd #>
        $color = if(($e.State -band [System.Windows.Forms.DrawItemState]::Selected) -eq [System.Windows.Forms.DrawItemState]::Selected){ 
            [System.Drawing.SystemColors]::Highlight
        }else{
            if($e.Index % 2 -eq 0){
                [System.Drawing.Color]::WhiteSmoke
            }else{
                [System.Drawing.Color]::White
            }
        }

        # Background item brush
        $backgroundBrush = New-Object System.Drawing.SolidBrush $color
        # Text color brush
        $textBrush = New-Object System.Drawing.SolidBrush $e.ForeColor

        # Draw the background
        $e.Graphics.FillRectangle($backgroundBrush, $e.Bounds)
        # Draw the text
        $e.Graphics.DrawString($s.Items[$e.Index], $e.Font, $textBrush, $e.Bounds.Left, $e.Bounds.Top, [System.Drawing.StringFormat]::GenericDefault)

        # Clean up
        $backgroundBrush.Dispose()
        $textBrush.Dispose()
    }
    $e.DrawFocusRectangle()
})

Et voila:

Alternate row colors in ListBox

Comments