Reputation: 335
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
Upvotes: 0
Views: 1659
Reputation: 1868
By the looks of your code, you aren't using XAML, but I wanted to add this anyways as an alternative approach.
You can set this by setting up a style trigger by writing XAML as your front end code for the UI and specifying the setter properties within the trigger. Then within your ListBox control, you can specify the name of the style that you created on the ItemContanerStyle property and specify an AlertnationCount of 2 so it highlights each row with the colors you specified.
My example below shows how it works as you add text to the list box.
#Build the GUI
[xml]$xaml = @"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen"
Width = "313" Height = "800" ShowInTaskbar = "True" Background = "lightgray">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel >
<StackPanel.Resources>
<Style x:Key="AlternatingRowStyle" TargetType="{x:Type Control}" >
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="Black"/>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBox IsReadOnly="True" TextWrapping="Wrap">
Type something and click Add
</TextBox>
<TextBox x:Name = "inputbox"/>
<Button x:Name="button1" Content="Add"/>
<Button x:Name="button2" Content="Remove"/>
<Expander IsExpanded="True">
<ListBox x:Name="listbox" SelectionMode="Extended" AlternationCount="2"
ItemContainerStyle="{StaticResource AlternatingRowStyle}"/>
</Expander >
</StackPanel>
</ScrollViewer >
</Window>
"@
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load( $reader )
#region Connect to Controls
Write-Verbose "Connecting to controls"
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach {
New-Variable -Name $_.Name -Value $Window.FindName($_.Name) -Force
}
#endregion Connect to Controls
$Window.Add_SourceInitialized({
#Have to have something initially in the collection
$Script:observableCollection = New-Object System.Collections.ObjectModel.ObservableCollection[string]
$listbox.ItemsSource = $observableCollection
$inputbox.Focus()
})
#Events
$button1.Add_Click({
$observableCollection.Add($inputbox.text)
$inputbox.Clear()
})
$button2.Add_Click({
ForEach ($item in @($listbox.SelectedItems)) {
$observableCollection.Remove($item)
}
})
$Window.ShowDialog() | Out-Null
Upvotes: 0
Reputation: 174815
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:
Upvotes: 1