Search code examples
wpfpowershelldata-bindingcomboboxdatagrid

PowerShell WPF - Binding DataGrid ComboBox to Column In ItemsSource


I am trying to populate a ComboBox within a DataGrid with unique values from a given column, however I'm getting unexpected results in that it splits the value from that row into individual characters and populates each ComboBox with said characters.

Here's a simple example script of my issue;

$csv = "ID,Fruit,Owner`r`n"
$csv += "1,Apple,Andrew`r`n"
$csv += "2,Banana,Bill`r`n"
$csv += "3,Cherry,Charles`r`n"
$csv += "4,Date,Daniel`r`n"
$csv += "5,Elderberry,Ethan`r`n"

$data = ConvertFrom-Csv $csv

$inputXML = @"
<Window x:Name="DataGridComboTest" x:Class="DataGridComboTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataGridComboTest" Width="640" Height="480" WindowStartupLocation="CenterScreen">
    <Grid>
        <DataGrid x:Name="DataGrid" Margin="10,10,10,10" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding ID}" Header="ID"/>
                <DataGridTextColumn Binding="{Binding Fruit}" Header="Fruit"/>
                <DataGridTextColumn Binding="{Binding Owner}" Header="Owner"/>

                <DataGridTemplateColumn Header="Owner Combo">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox
                                SelectedItem="{Binding Path=Owner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                ItemsSource="{Binding Owner}"
                                Text="{Binding Path=Owner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                            </ComboBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>
"@

$inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N'  -replace '^<Win.*', '<Window'
[void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
[xml]$XAML = $inputXML

$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Form=[Windows.Markup.XamlReader]::Load( $reader )
$xaml.SelectNodes("//*[@Name]") | %{ Set-Variable -Name "$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop }

$DataGrid.ItemsSource = $data

$Form.ShowDialog() | Out-Null

What I'd like to be able to do is select a different owner for each fruit from the existing owners in the table, however instead I'm given a choice of each letter in the adjacent owner's name;

Example screenshot


Solution

  • You should bind the ItemsSource to an IEnumerable<string> rather than a scalar string (which is an IEnumerable<char>).

    Try something like this:

    ...
    ItemsSource="{DynamicResource owners}"
    ...
    
    $owners = $data | Select-Object -ExpandProperty Owner -Unique
    $Form.Resources.Add("owners", $owners)