Binding RadioButton IsChecked for ListBoxItem IsSelected and ListBox IsFocused
I've seen other questions very similar to this, but somehow I still can't get it to work. Here's the script.
What I have
I have ListBox
that displays a list of my view models. Each view model has a list of children that appear in another, nested list. I am using DataTemplate
to achieve this.
What I want
I want the children elements to have RadioButton
which is selectable when selected ListBoxItem
and when ListBox
has focus (inner ListBox
).
Currently the part IsSelected
above works fine, however when I switch from one viewmodel to another (i.e. the first ListBox loses focus) the radio button on the first one ListBox
remains selected.
Here is the code:
<Style TargetType="{x:Type ListBox}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<RadioButton Focusable="False">
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsFocused, Mode=OneWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}" Value="False">
<Setter Property="IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
<RadioButton.IsChecked>
<Binding Path="IsSelected" Mode="TwoWay" RelativeSource="{RelativeSource TemplatedParent}" />
</RadioButton.IsChecked>
<ContentPresenter></ContentPresenter>
</RadioButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
I also tried MultiBinding
but that didn't work either. Any suggestions?
UPDATE
Update to include my attempt in MultiBinding
:
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<RadioButton>
<RadioButton.IsChecked>
<MultiBinding>
<MultiBinding.Converter>
<DataExportTool:AllTrueConverter/>
</MultiBinding.Converter>
<Binding Path="IsSelected" Mode="TwoWay" RelativeSource="{RelativeSource TemplatedParent}"/>
<Binding Path="IsFocused" Mode="OneWay" RelativeSource="{RelativeSource TemplatedParent}"/>
</MultiBinding>
</RadioButton.IsChecked>
<ContentPresenter/>
</RadioButton>
</ControlTemplate>
And the converter:
public class AllTrueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.Cast<bool>().All(x => x);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return Enumerable.Repeat((bool)value, 2).Cast<object>().ToArray();
}
}
Some of this IsSelected
works great, i.e. only one item in the list has a radio balance selected at any time. However, when the control loses focus, the selected radio button is still selected (not what I want).
source to share
Here is the xaml that ended up working. Disabling the toggle seems to be the key here.
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<RadioButton x:Name="rbIsSelected" IsChecked="False" IsEnabled="False" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="3" />
<ContentPresenter Grid.Column="1"/>
</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>
Finding the default template helped a lot.
source to share
Use MultiBinding instead of regular Binding, you also need IMultiValueConverter here:
<RadioButton.IsChecked>
<Binding Path="IsSelected" Mode="TwoWay" RelativeSource="{RelativeSource TemplatedParent}" />
</RadioButton.IsChecked>
I usually make these examples myself, but this link should give you a good idea on how to use them. If not, I'll make a simplified example later.
Basically, you want to send IsFocused and IsSelected Dependency properties to MultiBinding, then in MultiValueConverter say something like
return (bool)value[0] && (bool)value[1];
Where value [0] is IsFocused and value 1 isSelected, or vice versa.
Good luck!
source to share