I have a generic style for a ListBox
that overwrites the ItemTemplate
to use RadioButtons
. It works great, EXCEPT when I set a DisplayMemberPath
. Then I just get the .ToString()
of the item in the ListBox
.
I feel like I'm missing something simple here... can someone help me spot it?
<Style x:Key="RadioButtonListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2, 2, 2, 0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Background="Transparent">
<RadioButton
Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"
IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
My ListBox
is bound to a List<T>
of KeyValuePairs
. If I remove the Style, the DisplayMemberPath
shows up correctly so it must be something with the style.
<ListBox Style="{StaticResource RadioButtonListBoxStyle}"
ItemsSource="{Binding MyCollection}"
DisplayMemberPath="Value" SelectedValuePath="Key" />
I have been researching this same problem since morning and this thread helped me a lot. I investigated the solution and found out there is a way to support DisplayMemberPath even after defining a custom ListboxItem controltemplate in a style . The key is adding
to the contentpresenter( the radiobutton in case of this thread).
The reason this will work is because internally the displaymemberpath property causes the Listbox to assign the ContentTemplateSelector to a "DisplayMemberTemplateSelector" template selector. Without this TemplateBinding in place, this selector does not take effect.
Cheers!
Why exactly do you want to keep DisplayMemberPath? Its just a shortcut for an ItemTemplate containing a TextBlock showing the value in DisplayMemberPath. With your own ItemTemplate you have much more flexibility what and how you want to display. Just add a TextBlock into your ItemTemplate and set
Text="{Binding Value}"
and you have what you want.As described here
DisplayMemberPath provides a simple way to a Template, but you want a different one. You can't and you don't need both.
tl;dr
Set an ItemContainerStyle with a ContentPresenter in it, and make sure not to overwrite the ItemTemplate.
The need
You want to define a generic style to be re-used.
You want to re-use it with different data types, so you want to be able to use DisplayMemberPath or ItemTemplate when re-using - without having to redefine the whole style.
The problem
You were not using a ContentPresenter on your item's container.
The item itself would have nowhere to be drawn.
The solution
For your concrete case
Put a ContentPresenter inside the RadioButton; that should work:
In general
Define the ItemContainerStyle. This lets you control how each item is wrapped.
That Style targets a ListBoxItem.
Define that style's Template, making sure to include a ContentPresenter (where the content of the item itself will be shown).
A sample
Defining the style Using itI still can't figure out how to get it to draw using the
DisplayMemberPath
, however I did find the piece I was missing to get it drawing using theItemTemplate
- I needed theContentTemplate
bindingThen in my XAML I can write:
Thanks to dowhilefor for pointing out that
DisplayMemberPath
is simply a shortcut way of writing theItemTemplate
, and that both cannot be set at once.