How to make a custom focused effect be visible only if the keyboard navigation mode is on in WPF?

61 Views Asked by At

I have to use a custom template for a WPF control (a RadioButton) and the control has to have a custom implementation of the Focused effect. Because of that don't use the FocusVisualStyle property but implement the effect inside the control template and I want to use the ControlTemplate's Triggers to enable or disable the effect like that:

<ControlTemplate.Triggers>
    <Trigger Property="IsKeyboardFocused" Value="True">
        <Setter TargetName="FocusEffect" Property="Visibility" Value="Visible" />
    </Trigger>
</ControlTemplate.Triggers>

But the problem is that the default Windows behaviour is that the focus effect is visible only when the keyboard navigation mode is on (the user used the Tab key or pressed the Alt key). If I use only the IsKeyboardFocused property, I have the effect even if the control has been clicked with the mouse which should not be the case.

Which property (properties) do I need to use as a trigger to achieve the default behaviour?

2

There are 2 best solutions below

0
emoacht On BEST ANSWER

In fact, you can freely design a Style for FocusVisualStyle. It merely defines a control to be overlayed.

A Style to surround the RadioButton's mark would be like the following.

<Style x:Key="OptionMarkFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle Width="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}"
                           HorizontalAlignment="Left"
                           Stroke="Black"
                           StrokeThickness="1"
                           StrokeDashArray="1 2"
                           SnapsToDevicePixels="True"/>               
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<StackPanel>
    <RadioButton FocusVisualStyle="{StaticResource OptionMarkFocusVisual}" Content="AAA"/>
    <RadioButton FocusVisualStyle="{StaticResource OptionMarkFocusVisual}" Content="BBB"/>
    <RadioButton FocusVisualStyle="{StaticResource OptionMarkFocusVisual}" Content="CCC"/>
</StackPanel>

You can create alternative Styles as you wish.

Octagon:

<Style x:Key="OptionMarkFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid HorizontalAlignment="Left"
                      SnapsToDevicePixels="True">
                    <Polygon Points="1,0 3,0 4,1 4,3 3,4 1,4 0,3 0,1"
                             Stretch="Uniform"
                             Stroke="Black"
                             StrokeThickness="1"
                             StrokeDashArray="1 2"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Crosshair:

<Style x:Key="OptionMarkFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>                
                <Grid HorizontalAlignment="Left"
                      SnapsToDevicePixels="True"
                      UseLayoutRounding="True">
                    <Path Data="M 1,0 L 1,2 M 0,1 L 2,1"
                          Stretch="Uniform"
                          Stroke="Gray"
                          StrokeThickness="1"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
0
mm8 On

Which property (properties) do I need to use as a trigger to achieve the default behaviour?

I am afraid there is no dependency property that you can use to determine whether last input was from the keyboard.

And yes, the FocusVisualStyle is programmatically applied as an adorner on top of the focused control.

So to solve this, you will need to implement some kind of focus detection functionality that programmatically focuses the element in your template.