一、WPF中的焦点
在 WPF 中,有两个与焦点有关的主要概念:键盘焦点和逻辑焦点。 键盘焦点指接收键盘输入的元素,而逻辑焦点指焦点范围中具有焦点的元素。
参与焦点管理的主要类包括 Keyboard 类、 FocusManager 类和基元素类,如 UIElement 和 ContentElement 。
Keyboard类主要与键盘焦点相关,并 FocusManager 主要与逻辑焦点相关,但这并不是绝对差别。 具有键盘焦点的元素也具有逻辑焦点,但具有逻辑焦点的元素不一定具有键盘焦点。
二、键盘焦点
键盘检点指当前正在接收键盘输入的元素。在整个桌面上,只有一个具有键盘检点的元素。在WPF中,具有键盘焦点的元素将IsKeyboardFocused 设置为 true
。 FocusedElement类上的静态属性 Keyboard 获取当前具有键盘焦点的元素。
为了使元素能够获取键盘焦点, Focusable IsVisible 基本元素上的和属性必须设置为 true
。 某些类,如 Panel 基类, Focusable 默认情况下将设置为 false
; 因此, Focusable true
如果希望此类元素能够获取键盘焦点,则必须将设置为。(可见、并可设置焦点)
编码实现某控件获取焦点
Keyboard.Focus(firstButton);
三、逻辑焦点
逻辑焦点引用 FocusManager.FocusedElement 焦点范围内的。 焦点作用域是跟踪 FocusedElement 其作用域内的的元素。 键盘焦点离开焦点范围时,焦点元素会失去键盘焦点,但保留逻辑焦点。 键盘焦点返回到焦点范围时,焦点元素会再次获得键盘焦点。 这使得键盘焦点可在多个焦点范围之间切换,但确保了焦点返回到焦点范围时,焦点范围中的焦点元素重新获得键盘焦点。
FocusManager 附加属性设置 IsFocusScope 为,可以在中将元素转换为焦点范围 true
。 在代码中,可以通过调用将元素转换为焦点范围 SetIsFocusScope 。
xaml中
<StackPanel Name="focusScope1" FocusManager.IsFocusScope="True" Height="200" Width="200"> <Button Name="button1" Height="50" Width="50"/> <Button Name="button2" Height="50" Width="50"/> </StackPanel>
.cs代码
StackPanel focuseScope2 = new StackPanel(); FocusManager.SetIsFocusScope(focuseScope2, true);
焦点范围一般是 Window 和的类 MenuItem 、ToolBar 、ContextMenu 、PopUp(独立焦点)
GetFocusedElement 获取指定焦点范围的聚焦元素。 SetFocusedElement 设置指定焦点范围中的焦点元素。 SetFocusedElement 通常用于设置初始聚焦元素。
// Sets the focused element in focusScope1 // focusScope1 is a StackPanel. FocusManager.SetFocusedElement(focusScope1, button2); // Gets the focused element for focusScope 1 IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);
四、键盘导航
KeyboardNavigation类负责在按下一个导航键时实现默认键盘焦点导航。 导航键包括:Tab、Shift+Tab、Ctrl+Tab、Ctrl+Shift+Tab、向上键、向下键、向左键和向右键。
可以通过设置附加的 KeyboardNavigation 属性、和来更改导航容器的导航行为 TabNavigation ControlTabNavigation DirectionalNavigation 。 这些属性的类型为 KeyboardNavigationMode ,可能的值为 Continue 、 Local 、 Contained 、 Cycle 、 Once 和 None 。 默认值为 Continue ,这意味着该元素不是导航容器。
五、编程方式控制焦点
用于处理焦点的其他 API 为 MoveFocus 和 PredictFocus 。
MoveFocus 将焦点更改为应用程序中的下一个元素。 TraversalRequest用于指定方向。 FocusNavigationDirection传递的用于 MoveFocus 指定可以移动的不同方向焦点,如 First 、 Last Up 和 Down 。
// Creating a FocusNavigationDirection object and setting it to a // local field that contains the direction selected. FocusNavigationDirection focusDirection = _focusMoveValue; // MoveFocus takes a TraveralReqest as its argument. TraversalRequest request = new TraversalRequest(focusDirection); // Gets the element with keyboard focus. UIElement elementWithFocus = Keyboard.FocusedElement as UIElement; // Change keyboard focus. if (elementWithFocus != null) { elementWithFocus.MoveFocus(request); }
六、焦点事件
与键盘焦点相关的事件为 PreviewGotKeyboardFocus 、 GotKeyboardFocus 和 PreviewLostKeyboardFocus LostKeyboardFocus 。 事件在类上定义为附加事件 Keyboard ,
七、跨进程和窗口控制焦点
win32API
SetFocus(hwnd);
八、复合控件的焦点控制
1、 自定义控件
- 在UserControl标记中
<UserControl KeyboardNavigation.ControlTabNavigation="Local" IsTabStop="False">
KeyboardNavigation.ControlTabNavigation="Local" 设置焦点导航的方式,local可以把自定义控件中的子控件当做是引用窗体中的同级控件一样对待。
IsTabStop="False" 防止焦点中断,为了保证封装性,建议在这里设置。
- 子控件的TabIndex从父控件中获取
<TextBox x:Name="txt2" TabIndex="{Binding Path=TabIndex, RelativeSource={RelativeSource AncestorType={x:Type local:CustomControl}}}"/>
CustomControl是自定义控件的名称。
如果有多个子控件,建议调整标签的前后顺序。
2、 窗体
设置控件的TabIndex属性,也可以使用KeyboardNavigation.TabIndex。
九、
<TextBox Height="30" Name="txtUserName" Text="{Binding UserNme}"> <TextBox.Style> <Style TargetType="TextBox"> <Style.Triggers> <DataTrigger Binding="{Binding IsFocus}" Value="True"> <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=txtUserName}"/> </DataTrigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox>
<TextBox x:Name="txt" > <TextBox.Style> <Style TargetType="TextBox"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TextBox"> <Grid FocusManager.FocusedElement="{Binding ElementName=btn123}"> <Button x:Name="btn123" Content="123" Margin="10"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </TextBox.Style> </TextBox>
Combobox.focus()获取焦点
xt1.TabIndex = -1;就失去了焦点
十、焦点样式
焦点视觉样式的用途
焦点视觉样式功能提供一种通用“对象模型”,用于基于任何 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 中每个可通过键盘获得焦点的元素的样式。
十一、利用焦点事件更改颜色
<StackPanel> <StackPanel.Resources> <Style TargetType="{x:Type Button}"> <Setter Property="Height" Value="20"/> <Setter Property="Width" Value="250"/> <Setter Property="HorizontalAlignment" Value="Left"/> </Style> </StackPanel.Resources> <Button GotFocus="OnGotFocusHandler" LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyboard Focus</Button> <Button GotFocus="OnGotFocusHandler" LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyborad Focus</Button> </StackPanel>