Reputation: 1226
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;
Upvotes: 1
Views: 2439
Reputation: 169360
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)
Upvotes: 1
Reputation: 1226
With mm8's help I was able to come up with a working script;
$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"
$csv += "6,Fig,Bill`r`n"
$csv += "7,Grape,Daniel`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="{DynamicResource owners}"
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
#$owners = [Linq.Enumerable]::ToArray($data | Select-Object -ExpandProperty Owner)
$owners = $data | Select-Object -ExpandProperty Owner -Unique
$Form.Resources.Add("owners", $owners)
$Form.ShowDialog() | Out-Null
The DynamicResource binding was key, but the [Linq.Enumerable] line from mm8's answer threw an error. However simplifying it to select unique owners from $data resolved this. I also added a couple of duplicate owners to the source data to more accurately simulate a real-world scenario, hence "-Unique".
Upvotes: 1