dumbledad
dumbledad

Reputation: 17527

Adding a RadioButton to a WPF ListItem in XAML using a ControlTemplate

Following gehho's answer to "MVVM Group Radio Button" I'm trying to add a radio button to a list item such that when the list item is selected the radio button gets checked, and when the list item is not selected the radio button is unchecked. Kelly has a great answer to his or her "Binding RadioButton IsChecked to ListBoxItem IsSelected and ListBox IsFocused" question that looks like it should do what I need. However my simple transposition of Kelly's XAML is not working - the radio buttons remain unchecked. Here is the entirety of my MainWindow.xaml

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.SampleDataSource" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="RadioButton.MainWindow"
    x:Name="Window"
    Title="MainWindow"
    Width="640" Height="480">

    <Window.Resources>
        <SampleData:SampleDataSource x:Key="SampleDataSource" d:IsDataSource="True"/>
        <ControlTemplate x:Key="LBItemControlTemplate" TargetType="{x:Type ListBoxItem}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="20"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock TextWrapping="Wrap" Text="{Binding Property1}" Grid.Column="1"/>
                <RadioButton x:Name="rbIsSelected" IsChecked="False" IsEnabled="False"/>
            </Grid>
            <ControlTemplate.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="True"/>
                        <Condition Property="Selector.IsSelectionActive" Value="True"/>
                    </MultiTrigger.Conditions>
                    <Setter Property="IsChecked" TargetName="rbIsSelected" Value="True"/>
                </MultiTrigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <DataTemplate x:Key="ListBoxItemTemplate">
            <ListBoxItem Template="{StaticResource LBItemControlTemplate}"/>
        </DataTemplate>
    </Window.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
        <ListBox ItemsSource="{Binding Collection}" ItemTemplate="{DynamicResource ListBoxItemTemplate}" SelectionMode="Single"/>
    </Grid>
</Window>

Can anyone see why this is not working and suggest a fix or a different approach?

Upvotes: 0

Views: 1606

Answers (1)

dowhilefor
dowhilefor

Reputation: 11051

Do you know that ItemsControls will automatically create a Container item for every data item found? Your DataTemplate contains a ListBoxItem which is never correct. You basically say "When you display my content in a ListBoxItem, create a new ListBoxItem". So your code relys on your detached ListBoxItem, which can never be selected, because its not a container item in an ItemsControl, therefore it can't work. Your DataTemplate is only the content inside the Container, in this case the DataTemplate should define how your data should look in a ListBoxItem.

This is a small but not necessarly good practice example, but it shows that you don't have to create a ListBoxItem, it is automatically there:

Somewhere as a resource, Window.Resources or app.xaml for example:

<DataTemplate x:Key="myTemplate">
    <StackPanel Orientation="Horizontal">
        <CheckBox IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"/>
        <TextBlock Text="{Binding}"/>
    </StackPanel>
</DataTemplate>

And the usage itself

<ListBox x:Name="test" ItemTemplate="{StaticResource myTemplate}"/>

The listbox in this case would need to get an ItemsSource set in the code behind.

Upvotes: 1

Related Questions