简体   繁体   中英

How do WPF buttons decide to show FocusVisualStyle?

I would like to trigger a change in a Button's template to complement the FocusVisualStyle effects. Basically I want the text 'foo' in the snippet below to turn red if and only if FocusVisualStyle is visible:

<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Grid>
                    <ContentPresenter/>
                    <TextBlock x:Name="TxtFoo" Text="foo" Foreground="Black"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsKeyboardFocused" Value="true">
                        <Setter Property="Foreground" TargetName="TxtFoo" Value="Red"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Please ignore the fact that the example is idiotic, the actual code is more useful (it modifies a Path).

This works on keyboard navigation, but has an issue: the text turns red also when the button is pressed (FocusVisualStyle is not displayed in that case). Using an eventTrigger on GotKeyboardFocus/LostKeyboardFocus yields the same result.

Looking at the framework's source code I don't see anything special: KeyboardNavigation.ShowFocusVisual() is called by FrameworkElement.OnGotKeyboardFocus() as expected. However, obviously there must be something else going on because not every gotKeyboardFocus events cause FocusVisualStyle to show.

What property/event should I target if I want to be "synchronized" with FocusVisualStyle?

Silly question maybe, but why don't you simply copy the FocusVisualStyle (in Blend) and edit it to display what you want? This is the way we normally do these things.

Cheers, Laurent

而不是使用IsKeyboardFocused尝试IsFocused

Found by rummaging through .net core sources for Wpf, but it works brilliantly for WPF 4.7.2 as well....

For a normal control, the FocusVisualStyle is applied only if the keyboard was the most recent input device. Unfortunately, there is no way to make the FocusVisualStyle dependent on the state of the control to which it is applied; and there is no out-of-the-box property, event or attached property which can be used to detect FocusVisualStyle state.

The solution is to provide a derived dependency property on your control, and then emulate FocusVisualStyle in the control template using triggers.

Include the following code in your Control, and trigger off the IsVisualFocus property in your control template, which will be true only when FocusVisualStyle would have been applied.

protected override void OnGotFocus(RoutedEventArgs e)
{
    base.OnGotFocus(e);
    IsVisualFocus = IsKeyboardMostRecentInputDevice();
}

protected override void OnLostFocus(RoutedEventArgs e)
{
    base.OnLostFocus(e);
    IsVisualFocus = false;
}

private bool IsKeyboardMostRecentInputDevice()
{
    return InputManager.Current.MostRecentInputDevice is KeyboardDevice;
}

public bool IsVisualFocus
{
    get { return (bool)GetValue(IsVisualFocusProperty); }
    set { SetValue(IsVisualFocusProperty, value); }
}

And then in the Control template...

     <Style x:Key="{x:Type local:FlatButton}" TargetType="local:FlatButton">
          <Setter Property="FocusVisualStyle" Value={x:Null}/> <!-- disable system FocusVisualStyle -->
          <Setter Property="Template">
                <Setter.Value>
                        <ControlTempalte.Triggers>
                              <Trigger Property="IsVisualFocus" Value="True">
                                       .... your setters here ....
                                       <Setter TargetName="T_Border" Property="Background" Value="#10FF0000"/>
                              </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>          
                </Setter.Value>
          </Setter>
   </Style>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM