How does one create two mutually excusive checkboxes in WPF (but allow them both to be unchecked)
I've been trying to make it impossible to have two checkboxes checked at the same time in WPF but still allowing them both to be unchecked.
Does anyone know how I can achieve this?
This is what I have at the moment. Unfortunately this has the behaviour that both triggers are called when a checkbox is checked.
<Window.Resources>
<Style x:Key="style1" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=checkBox2, Path=IsChecked}" Value="True">
<Setter Property="CheckBox.IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="style2" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=checkBox1, Path=IsChecked}" Value="True">
<Setter Property="CheckBox.IsChecked" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
开发者_C百科 <CheckBox Style="{StaticResource style1}" Name="checkBox1" Content="Check Box 1" />
<CheckBox Style="{StaticResource style2}" Name="checkBox2" Content="Check Box 2" />
</Grid>
Leverage ListBox
's exclusive single SelectionMode
for this...
<ListBox x:name="MyListBox"
xmlns:System="clr-namespace:System;assembly=mscorlib"
SelectionMode="Single">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<SolidColorBrush
x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent"/>
</Style.Resources>
</Style>
</ListBox.Resources>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"
Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox
Content="{Binding}"
IsChecked="{Binding
IsSelected,
RelativeSource={RelativeSource
AncestorType={x:Type ListBoxItem}},
Mode=TwoWay}"
Margin="5"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsSource>
<x:Array Type="{x:Type System:String}">
<System:String>My Checkbox 1</System:String>
<System:String>My Checkbox 2</System:String>
</x:Array>
</ListBox.ItemsSource>
</ListBox>
So for "n" mututally exclusive checkboxes simply add those many number of strings to the x:Array
above. The above functionality works great fo radioboxes too.
As you have said, the checkboxes will allow none or only one checked. And then to access which one is actually checked, MyListBox.SelectedIndex
will help you.
Instead of using a Checkbox
, restyle a RadioButton
instead.
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RadioButton}">
<CheckBox x:Name="Checkbox" IsChecked="{Binding Path=IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWayToSource}"
Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource TemplatedParent}}" Value="{x:Null}">
<Setter TargetName="Checkbox" Property="IsChecked" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource TemplatedParent}}" Value="False">
<Setter TargetName="Checkbox" Property="IsChecked" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="Checkbox" Property="IsChecked" Value="True"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
To allow both to be unchecked, create a trigger that handles the {x:Null}
value. I have implement such a trigger, however have not tested if it would work (let me know if you have trouble with it).
You could achieve the desired effect with two lines of C# code:
CheckBox1.Checked += (sender, e) => { CheckBox2.IsChecked = false; };
CheckBox2.Checked += (sender, e) => { CheckBox1.IsChecked = false; };
精彩评论