Search code examples
wpfpowershellxamlcheckboxlist

How to programmatically click a CheckListBox in WPF?


I have tried binding a CheckBox IsChecked to IsSelected of a ListBoxItem in xaml. This way I can populate a dynamic list with corresponding checkboxes and I receive a list of checked items using the form. So far so good. But, how do I precheck items in the list programmatically, preferable in PowerShell?

I have been testing with a XAML that looks like this:

<Window x:Class="WpfHandler.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfHandler"
        mc:Ignorable="d"
         Title="Testing" Height="300" Width="250">

    <Window.Resources>
        <Style TargetType="ListBoxItem">
            <Setter Property="OverridesDefaultStyle" Value="true" />
            <Setter Property="SnapsToDevicePixels" Value="true" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <CheckBox Margin="5,2" IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource TemplatedParent}}">
                            <ContentPresenter />
                        </CheckBox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Border Padding="10">
        <Grid Margin="0 10 0 10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <StackPanel Name="Testing" Orientation="Horizontal">
                <ListBox Name="Box_Test" ItemsSource="{DynamicResource test}" Height="220" SelectionMode="Multiple"/>
            </StackPanel>
        </Grid>
    </Border>
</Window>

...and a Powershell script that looks like this:

add-type -AssemblyName PresentationFramework
Add-Type -AssemblyName System.Drawing

$xamlFile = "testing.xaml"
   
[xml]$xaml = (Get-Content $xamlFile -Raw) -replace 'x:Name', 'Name'
$xaml.Window.RemoveAttribute('x:Class')
$xaml.Window.RemoveAttribute('mc:Ignorable')
$xaml.SelectNodes("//*") | ForEach-Object {
    $_.RemoveAttribute('d:LayoutOverrides')
}

$reader = (New-Object System.Xml.XmlNodeReader $xaml) 
try {
    $Script:Form = [Windows.Markup.XamlReader]::Load( $reader )
    # Get Name variables from form and set scope to script
    $xaml.SelectNodes("//*[@Name]") | ForEach-Object { Set-Variable -Name ($_.Name) -Value $Script:Form.FindName($_.Name) -Scope script }
}
catch {
    Write-Host "Unable to load Windows.Markup.XamlReader"; 
    exit
}

$testdata = Get-Content "testdata.txt"

$Script:Form.Resources.Add("test", $testdata)
$Script:Form.ShowDialog()

Solution

  • Here is an example to select the first two items by index:

    $Script:Form.Add_Loaded({
        foreach( $i in 0, 1 ) {
            $Box_Test.ItemContainerGenerator.ContainerFromIndex( $i ).IsSelected = $true
        }
    })
    
    $Script:Form.ShowDialog()
    

    ItemContainerGenerator is a property of the ItemsControl base class of ListBox.