I have a DataGrid with a column that is a DataGridComboBoxColumn. For the items in those combo boxes I need to display an image and some text. Below is what I was able to do. But the initial binding isn't working. And once I select an item in the combobox the images all disappear in all the comboboxes.
Is what I am doing on the right path to getting this to work with some sort of trigger or binding I am missing? Or is there a better way to display both an image and text in a combobox in a datagrid?
<DataGridComboBoxColumn Header="Status" SelectedValueBinding="{Binding Status}" SelectedItemBinding="{Binding Status}" SelectedValuePath="Tag" xmlns:s="clr-namespace:System;assembly=mscorlib"
>
<DataGridComboBoxColumn.ItemsSource>
<x:Array Type="{x:Type StackPanel}">
<StackPanel Orientation="Horizontal">
<Image Source="{DynamicResource DispatchedImage}">
</Image>
<TextBlock Text="DISP"/>
<StackPanel.Tag>
<s:String>"1"</s:String>
</StackPanel.Tag>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Image Source="{DynamicResource ConfirmedImage}">
</Image>
<TextBlock Text="CONF"/>
<StackPanel.Tag>
<s:String>"2"</s:String>
</StackPanel.Tag>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Image Source="{DynamicResource PickedUpImage}">
</Image>
<TextBlock Text="P/U"/>
<StackPanel.Tag>
<s:String>"3"</s:String>
</StackPanel.Tag>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Image Source="{DynamicResource DeliveredImage}">
</Image>
<TextBlock Text="DEL"/>
<StackPanel.Tag>
<s:String>"4"</s:String>
</StackPanel.Tag>
</StackPanel>
</x:Array>
</DataGridComboBoxColumn.ItemsSource>
</DataGridComboBoxColumn>
CodePudding user response:
You should bind the ItemsSource
of the ComboBox
to an IEnumerable<T>
where T
is a type that has a property for the display value and the id value:
public class CustomerComboBoxItem
{
public string Name { get; set; }
public int Value { get; set; }
}
Add the following property to your view model:
public CustomerComboBoxItem[] Items { get; } = new CustomerComboBoxItem[]
{
new CustomerComboBoxItem(){ Name ="DISP", Value = 1 },
new CustomerComboBoxItem(){ Name ="CONF", Value = 2 },
new CustomerComboBoxItem(){ Name ="P/U", Value = 3 },
new CustomerComboBoxItem(){ Name ="DEL", Value = 4 }
};
...and use an ItemTemplate
:
<DataGrid ...>
<DataGrid.Resources>
<DataTemplate x:Key="template">
<StackPanel Orientation="Horizontal">
<Image>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Text}" Value="DISP">
<Setter Property="Source" Value="{DynamicResource DispatchedImage}" />
</DataTrigger>
<DataTrigger Binding="{Binding Text}" Value="CONF">
<Setter Property="Source" Value="{DynamicResource ConfirmedImage}" />
</DataTrigger>
<DataTrigger Binding="{Binding Text}" Value="P/U">
<Setter Property="Source" Value="{DynamicResource PickedUpImage}" />
</DataTrigger>
<DataTrigger Binding="{Binding Text}" Value="DEL">
<Setter Property="Source" Value="{DynamicResource DeliveredImage}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Status"
SelectedValueBinding="{Binding Status}"
SelectedValuePath="Id">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.Items, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
<Setter Property="ItemTemplate" Value="{StaticResource template}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.Items, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
<Setter Property="ItemTemplate" Value="{StaticResource template}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
...
</DataGrid.Columns>
</DataGrid>
See the section on data templating in the docs for more information.