控件中的焦点样式,以及 FocusVisualStyle

Windows Presentation Foundation (WPF)提供了两种并行机制,用于在控件接收键盘焦点时更改控件的视觉外观。 第一种机制是在应用于控件的样式或模板中,为类似 IsKeyboardFocused 这样的属性使用属性设置器。 第二种机制是将一个单独的样式赋值为 FocusVisualStyle 属性的值;“焦点视觉样式”为绘制在控件顶部的修饰器创建了一个独立的可视化树,而不是通过替换控件或其他 UI 元素的可视化树来进行更改。 本主题讨论每种机制适用的情景。

焦点视觉样式的用途

焦点视觉样式功能提供了一个常见的“对象模型”,用于基于键盘导航引入任何 UI 元素的视觉用户反馈。 这可以在不向控件应用新模板或知道特定模板组合的情况下实现。

但是,正是因为焦点视觉样式功能在不知道控件模板的情况下有效,因此使用焦点视觉样式的控件可以显示的视觉反馈必然受到限制。 该功能的实际作用是将另一个可视化树(即装饰器)覆盖在由控件通过其模板渲染创建的可视化树之上。 使用填充属性的 FocusVisualStyle 样式定义此单独的可视化树。

默认焦点视觉样式行为

仅当通过键盘启动焦点时,焦点视觉样式才会起作用。 任何鼠标操作或程序中的焦点更改都会禁用焦点视觉样式模式。 有关焦点模式区别的详细信息,请参阅 焦点概述

控件的主题包括默认焦点视觉样式行为,该行为成为主题中所有控件的焦点视觉样式。 此主题样式由静态键 FocusVisualStyleKey的值标识。 在应用程序级别声明自己的焦点视觉样式时,就会替换主题中的默认样式行为。 或者,如果定义整个主题,则应使用相同的键来定义整个主题的默认行为的样式。

在主题中,默认焦点视觉样式通常非常简单。 下面是粗略近似值:

<Style x:Key="{x:Static SystemParameters.FocusVisualStyleKey}">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate>
        <Rectangle StrokeThickness="1"
          Stroke="Black"
          StrokeDashArray="1 2"
          SnapsToDevicePixels="true"/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

何时使用焦点视觉风格

从概念上讲,应用于控件的焦点视觉效果的外观应该在不同控件之间保持一致。 确保一致性的一种方法是仅在设计整个主题时才更改焦点视觉样式,其中主题中定义的每个控件将获得相同或相似的焦点视觉样式,或某种在控件之间视觉上相关的样式变体。 或者,可以使用同一样式(或类似样式)在页面或 UI 中设置每个可键盘焦点元素的样式。

对不属于主题的单个控件样式进行设置 FocusVisualStyle 不是焦点视觉样式的预期用法。 这是因为控件之间的不一致的视觉行为可能导致用户体验的混乱,特别是在键盘焦点方面。 如果您打算为在主题中故意不连贯的键盘焦点使用特定于控件的行为,更好的方法是对单个输入状态属性(例如 IsFocusedIsKeyboardFocused)在样式中使用触发器。

焦点视觉样式仅用于键盘焦点。 因此,焦点的视觉样式是一种无障碍功能。 如果需要在鼠标、键盘或编程方式聚焦时进行任何类型的 UI 更改,应避免使用焦点视觉样式,而应通过样式或模板中的 setter 和触发器,根据像 IsFocusedIsKeyboardFocusWithin 这样的常规焦点属性的值来实现。

如何创建焦点视觉样式

为焦点视觉样式创建的样式应始终具有 TargetTypeControl。 风格应主要由 ControlTemplate 组成。 您没有将目标类型指定为将焦点视觉样式分配给 FocusVisualStyle 的类型。

由于目标类型始终是 Control,因此必须使用对于所有控件通用的属性来进行样式设置(使用 Control 类及其基类的属性)。 应创建一个模板,该模板将正确用作 UI 元素的覆盖层,并且不会遮盖控件的功能区域。 通常,这意味着视觉反馈应出现在控件的边缘之外,或以临时的、不显眼的效果呈现,从而不会干扰应用了焦点视觉样式的控件的命中测试。 可以在模板绑定中使用的属性,这些属性可用于确定覆盖模板的大小和定位包括ActualHeightActualWidthMarginPadding

使用焦点视觉样式的替代方案

对于不合适使用焦点视觉样式的情况,要么是因为仅仅为单个控件设置样式,要么是希望更好地控制控件模板,有许多其他可用的属性和技术可以创建视觉效果,以响应焦点的变化。

样式和模板中详细讨论了触发器、设定器和事件设定器。 在路由事件概述中讨论了路由事件的处理。

IsKeyboardFocused (是否键盘聚焦)

如果您特别关注键盘焦点,那么可以将 IsKeyboardFocused 依赖属性用于属性 Trigger。 样式或模板中的属性触发器是一种更合适的技术,用于定义一个非常特定于单个控件的键盘焦点行为,并且可能无法直观地与其他控件的键盘焦点行为匹配。

另一个类似的依赖属性是 IsKeyboardFocusWithin,如果想要直观地标注键盘焦点位于组合或控件的功能区域内,则可能适合使用此属性。 例如,可以放置一个 IsKeyboardFocusWithin 触发器,以便将多个控件分组的面板以不同的方式显示,即使键盘焦点可能更准确地放在该面板内的单个元素上。

还可以使用事件 GotKeyboardFocusLostKeyboardFocus (以及其预览版等效项)。 可以将这些事件用作 EventSetter 的基础,或者编写后台代码中的事件处理程序。

其他焦点属性

如果希望更改焦点的所有可能原因产生视觉行为,应该基于IsFocused依赖属性来设置设置器或触发器,或者基于用于EventSetterGotFocusLostFocus事件。

另请参阅