I'm needing to style a three-state checkbox as a user-selectable control with three toggle buttons for the true/indeterminate/false values of the checkbox's IsChecked. The issue I'm encountering, and I can't wrap my brain around, is when selecting the indeterminate value the false value is also selected.
I've found if I don't explicitly direct the order of the checkbox clicks in the code behind only the true/false values are enabled. I have a feeling I'm stepping on my own toes or screwing up the data triggers somewhere, but I can't put my finger on it. Any ideas? (I appreciate all the help!)
Below is my xaml:
<Style x:Key="ThreeStateToggleCheckboxStyle"
TargetType="{x:Type CheckBox}"
BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="SnapsToDevicePixels"
Value="true" />
<Setter Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter Property="Background"
Value="{StaticResource EnabledControlBackgroundBrush}" />
<Setter Property="Foreground"
Value="{StaticResource EnabledTextBrush}" />
<Setter Property="BorderBrush"
Value="{StaticResource EnabledControlBorderBrush}" />
<Setter Property="BorderThickness"
Value="1" />
<Setter Property="IsThreeState"
Value="True" />
<Setter Property="VerticalAlignment"
Value="Center" />
<Setter Property="VerticalContentAlignment"
Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<ControlTemplate.Resources>
<converters1:BoolToNotBoolConverter x:Key="cbsB2NBConverter" FalseValue="True" TrueValue="False"/>
<converters1:NullToBoolConverter x:Key="nullToBConverter"
NullValue="True"
NotNullValue="False" />
<converters1:BoolToDoubleConverter x:Key="bool2ThreeStateOpacityConverter"
FalseValue="0.5"
TrueValue="1.0" />
</ControlTemplate.Resources>
<layoutControls:BorderControl x:Name="BackgroundBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderType="{TemplateBinding layoutControls:BorderControl.BorderType}"
DisabledBackgroundBrush="{TemplateBinding layoutControls:BorderControl.DisabledBackgroundBrush}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="ToggleYes"
Style="{StaticResource FlatToggleButtonStyle}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked, Mode=TwoWay}"
ClickMode="Press"
Focusable="False"
IsTabStop="False"
Margin="2"
Grid.Column="2">
<TextBlock x:Name="TextYes"
Text="Save"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="3,2"
Grid.Column="0" />
</ToggleButton>
<ToggleButton x:Name="ToggleNothing"
Style="{StaticResource FlatToggleButtonStyle}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked, Mode=TwoWay, Converter={StaticResource nullToBConverter}}"
ClickMode="Press"
Focusable="False"
IsTabStop="False"
Margin="2"
Grid.Column="1">
<TextBlock x:Name="TextNothing"
Text="Off"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="3,2"
Grid.Column="1" />
</ToggleButton>
<ToggleButton x:Name="ToggleNo"
Style="{StaticResource FlatToggleButtonStyle}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked, Mode=TwoWay, Converter={StaticResource invertBoolConverter}}"
ClickMode="Press"
Focusable="False"
IsTabStop="False"
Margin="2"
Grid.Column="0">
<TextBlock x:Name="TextNo"
Text="Send"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="3,2"
Grid.Column="2" />
</ToggleButton>
</Grid>
</layoutControls:BorderControl>
</ControlTemplate>
</Setter.Value>
</Setter>
This is the onLoaded event that sets the checkbox based on the VM bool value.
Private Sub ChkSaveOrSend_OnLoaded(sender As Object, e As RoutedEventArgs)
If chkSaveOrSend.IsChecked = False Then
chkSaveOrSend.IsChecked = If(chkSaveOrSend.IsThreeState, Nothing, (CType(True, Boolean?)))
Else
If ViewModel.ShouldSendQuote IsNot Nothing Then
chkSaveOrSend.IsChecked = ViewModel.ShouldSendQuote
End If
'chkSaveOrSend.IsChecked = New Boolean?(chkSaveOrSend.IsChecked.HasValue)
End If
End Sub
This is my hack-y workaround for trying to enable/disable the toggle buttons based on the checkbox.IsChecked value.
Private Sub tglShouldSendQuote_OnClick(sender As Object, e As RoutedEventArgs)
e.Handled = True
Dim senderElement = TryCast(sender, CheckBox)
senderElement.ApplyTemplate()
If senderElement IsNot Nothing Then
Dim yesButton = CType(senderElement.Template.FindName("ToggleYes", chkSaveOrSend), ToggleButton)
Dim noButton = CType(senderElement.Template.FindName("ToggleNo", chkSaveOrSend), ToggleButton)
Dim nothingButton = CType(senderElement.Template.FindName("ToggleNothing", chkSaveOrSend), ToggleButton)
If senderElement.IsChecked Then
yesButton.Opacity = 1
yesButton.IsEnabled = True
noButton.Opacity = 0.5
noButton.IsEnabled = False
nothingButton.IsEnabled = False
ElseIf Not senderElement.IsChecked _
AndAlso senderElement.IsChecked IsNot Nothing Then
noButton.Opacity = 1
noButton.IsEnabled = True
yesButton.Opacity = 0.5
yesButton.IsEnabled = False
nothingButton.IsEnabled = False
ElseIf senderElement.IsChecked Is Nothing Then
nothingButton.IsEnabled = True
yesButton.Opacity = 0.5
yesButton.IsEnabled = False
noButton.Opacity = 0.5
noButton.IsEnabled = False
End If
End If
End Sub
Aucun commentaire:
Enregistrer un commentaire