为控件中的焦点设置样式以及 FocusVisualStyle
更新:2007 年 11 月
Windows Presentation Foundation (WPF) 提供两种在控件接收键盘焦点时更改控件的可视外观的并行机制。第一种机制是对应用于控件的样式或模板中的属性(如 IsKeyboardFocused)使用属性 setter。第二种机制是将一个单独的样式作为 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 不是焦点视觉样式的预期用法。这是因为控件之间的不一致的可视行为会使用户对于键盘焦点感觉很混乱。如果您打算为键盘焦点设计特定于控件的行为,并且这些行为有意在主题中不一致,那么一种更好的方法是在样式中对个别的输入状态属性(如 IsFocused 或 IsKeyboardFocused)使用触发器。
焦点视觉样式专门作用于键盘焦点。同样,焦点视觉样式也是一种辅助功能。如果您希望针对任何类型的焦点来更改 UI(无论是通过鼠标、键盘还是编程方式),那么不应使用焦点视觉样式,而应在样式或模板中使用根据常规焦点属性(如 IsFocused 或 IsFocusWithin)的值发生作用的 setter 和触发器。
如何创建焦点视觉样式
为焦点视觉样式创建的样式始终应具有 Control 的 TargetType。样式应当主要包含 ControlTemplate。您不必将目标类型指定为将焦点视觉样式分配给了 FocusVisualStyle 的类型。
因为目标类型总是 Control,所以您必须通过使用所有控件共有的属性(使用 Control 类及其基类的属性)来设置样式。您应当创建将正确地用作 UI 元素的覆盖层并且不会隐藏控件的功能区域的模板。通常,这意味着可视反馈应显示在控件边距之外,或者显示为临时的或者不显眼的效果(不会阻止应用焦点视觉样式的控件上的命中测试)。可以在可用于确定覆盖模板的大小和位置的模板绑定中使用的属性包括 ActualHeight、ActualWidth、Margin 以及 Padding。
使用焦点视觉样式的替代方法
对于不适合使用焦点视觉样式的情形(或者是因为您仅仅设置单个控件的样式,或者是因为您希望对控件模板有更多的控制),也存在其他许多可访问的属性和技术,可用来创建响应焦点更改的可视行为。
触发器、setter 以及事件 setter 均在样式设置和模板化中详细介绍。路由事件处理在路由事件概述中介绍。
IsKeyboardFocused
如果您仅仅对键盘焦点感兴趣,那么 IsKeyboardFocused 依赖项属性可用于属性 Trigger。要定义特定于单个控件以及可能与其他控件的键盘焦点行为在视觉上不匹配的键盘焦点行为,样式或模板中的属性触发器是更适合的技术。
另一个类似的依赖项属性是 IsKeyboardFocusWithin,如果您希望从视觉上显示出键盘焦点在控件的组成或功能区域中的某处,那么可能适合使用此依赖项属性。例如,您可能放置一个 IsKeyboardFocusWithin 触发器,以便某个包含若干控件的面板以不同的样式显示,即使更精确地说,键盘焦点可能位于该面板中的某个元素上,此面板也以不同的样式显示。
您还可以使用事件 GotKeyboardFocus 和 LostKeyboardFocus(以及其 Preview 等效项)。您可以将这些事件用作 EventSetter 的基础,也可以通过代码隐藏为这些事件编写处理程序。
其他焦点属性
如果您希望更改焦点的所有可能原因都产生一个可视行为,那么应将 setter 或触发器基于 IsFocused 依赖项属性,或者基于用于 EventSetter 的 GotFocus 或 LostFocus 事件。