mercredi 14 août 2019

Why does clicking on the indeterminate value, in a three state combobox, cause the 'false' value to be enabled?

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.

Threestate toggle

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