简体   繁体   中英

WPF - FocusVisualStyle on moving

I have a UserControl with some buttons. My button have the default FocusVisualStyle (the border around the button).

When I move my user control with the mouse, this dotted border does not move with it. When you hover over another part of the screen it moves into the correct position.

I don't want to set the FocusVisualStyle to null, because I need to see what element is focused. I tried to create my own FocusVisualStyle but it behaves like the default one.

Can I somehow synchronize this border with the rest of the elements?

Thanks for help

As stated by bitbonk, the RenderTransform does not cause another arrange pass so the focus visual will not move. You can read this Dr. WPF article which discusses the issue as well as providing a couple of workarounds. The easiest in your case is to just put an AdornerDecorator within your UserControl around the content of your UserControl so that the AdornerLayer is moved too.

When you use RenderTransform the FocusVisualStyle rectangle is not moved with the button because it is rendered in the layout pass. That is the whole point of the RenderTransform : transform any visual and ignore the layout of the rest of the visual tree.

You will have to use LayoutTransform , or Button.Margin or Canvas.Left , Canvas.Top to move your button.

This (somewhat cryptic) excerpt from the MSDN speaks to the more general form of this issue:

Focus visual styles act exclusively for keyboard focus. As such, focus visual styles are a type of accessibility feature. If you want UI changes for any type of focus, whether via mouse, keyboard, or programmatically, then you should not use focus visual styles, and should instead use setters and triggers in styles or templates that are working from the value of general focus properties such as IsFocused or IsFocusWithin.

Today, that last bit about using triggers would probably be better replaced with a suggestion that you use the Visual State Manager. Here's some XAML that does it that way, but also preserves the original setting for a Button 's FocusVisualStyle . That setting draws a dashed rectangle two pixels inside a Button when it receives focus from the keyboard. My Storyboard s for the Focused and Unfocused visual states add and remove a solid rectangle, four pixels inside a Button , whenever it gains or loses the focus for any reason.

If you create a pair of Button s in a WPF Window and manipulate the focus by keyboard and by mouse, clicking those Button s with the spacebar and the mouse, you'll see that a Button often has the focus when the FocusVisualStyle doesn't appear. Again, this (according to the excerpt above) is by design. (I'm puzzled as to how this is an "accessibility feature," as it can easily neglect to show which control will be clicked the next time the spacebar is pressed. My inclination is just not to use it at all.)

NOTE: The code below is for a custom control derived from Button , called " XLButton ." You can change the Style 's TargetType to Button if you don't want to create a custom control to try this.

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ExLuminaControls">

<Style x:Key="FocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle Margin="2"
                           SnapsToDevicePixels="true"
                           Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
                           StrokeThickness="1"
                           StrokeDashArray="1 2"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>

<Style TargetType="{x:Type local:XLButton}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
    <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="{x:Null}"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:XLButton}">
                <Grid>
                    <Border x:Name="border"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}"
                            SnapsToDevicePixels="true"/>
                    <Rectangle x:Name ="glow" Fill="White" Opacity="0"/>
                    <Rectangle x:Name="shade" Fill="Black" Opacity="0"/>
                    <ContentPresenter x:Name="contentPresenter"
                                      Focusable="False"
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      Margin="{TemplateBinding Padding}"
                                      RecognizesAccessKey="True"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    <Rectangle x:Name="dis" Fill="Gray" Opacity="0"/>
                    <Rectangle x:Name="foc" Margin="4" SnapsToDevicePixels="true"
                               Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
                               StrokeThickness="1" Opacity="0"/>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup Name="CommonStates">
                            <VisualState Name="Normal">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="glow"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="0" Duration="0:0:.1"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState Name="MouseOver">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="glow"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To=".25" Duration="0:0:.1"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState Name="Pressed">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="shade"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To=".25" Duration="0:0:0"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState Name="Disabled">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="dis"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To=".25" Duration="0:0:0"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup Name="FocusStates">
                            <VisualState Name="Focused">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="foc"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="1" Duration="0:0:.1"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState Name="Unfocused">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="foc"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="0" Duration="0:0:.1"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
</ResourceDictionary>

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