WPF 中,有两个与焦点有关的主要概念:键盘焦点逻辑焦点。 键盘焦点指接收键盘输入的元素,而逻辑焦点指焦点范围中具有焦点的元素。 本概述将详细介绍这些概念。 理解这些概念之间的区别对于创建具有可以获取焦点的多个区域的复杂应用程序是非常重要的。

参与焦点管理的主要类有 Keyboard 类、FocusManager 类以及基元素类(如 UIElementContentElement)。 有关基元素的更多信息,请参见基元素概述

Keyboard 类主要与键盘焦点相关,而 FocusManager 则与逻辑焦点相关,但这种区别不是绝对的。 具有键盘焦点的元素也将具有逻辑焦点,但具有逻辑焦点的元素不一定具有键盘焦点。 当您使用 Keyboard 类来设置具有键盘焦点的元素时,这一点是很明显的,因为它还在元素上设置逻辑焦点。

键盘焦点


键盘焦点指当前正在接收键盘输入的元素。 在整个桌面上,只能有一个具有键盘焦点的元素。 在 WPF 中,具有键盘焦点的元素会将 IsKeyboardFocused 设置为 true。 Keyboard 类的静态属性 FocusedElement 获取当前具有键盘焦点的元素。

为了使元素能够获取键盘焦点,基元素的 FocusableIsVisible 属性必须设置为 true。 有些类(如 Panel 基类)默认情况下将 Focusable 设置为 false;因此,如果您希望此类元素能够获取键盘焦点,必须将 Focusable 设置为 true。

可以通过用户与 UI 交互(例如,按 Tab 键定位到某个元素或者在某些元素上单击鼠标)来获取键盘焦点。 还可以通过使用 Keyboard 类的 Focus 方法,以编程方式获取键盘焦点。 Focus 方法尝试将键盘焦点给予指定的元素。 返回的元素是具有键盘焦点的元素,如果有旧的或新的焦点对象阻止请求,则具有键盘焦点的元素可能不是所请求的元素。

下面的示例使用 Focus 方法在 Button 上设置键盘焦点。

 
 

private void OnLoaded(object sender, RoutedEventArgs e)
{
    // Sets keyboard focus on the first Button in the sample.
    Keyboard.Focus(firstButton);
}

基元素类的 IsKeyboardFocused 属性获取一个指示元素是否具有键盘焦点的值。 基元素类的 IsKeyboardFocusWithin 属性获取一个指示元素或者它的任何一个可视子元素是否具有键盘焦点的值。

当在应用程序启动时设置初始焦点时,接收焦点的元素必须连接到一个 PresentationSource,并且该元素必须将 FocusableIsVisible 设置为 true。 设置初始焦点的推荐位置是在 Loaded 事件处理程序中。 还可以通过调用 InvokeBeginInvoke 来使用 Dispatcher 回调。

逻辑焦点


逻辑焦点指焦点范围中的 FocusManager

.FocusedElement。 焦点范围是一个跟踪其范围内的 FocusedElement 的元素。 当键盘焦点离开焦点范围时,焦点元素会失去键盘焦点,但保留逻辑焦点。 当键盘焦点返回到焦点范围时,焦点元素会再次获得键盘焦点。 这使得键盘焦点可以在多个焦点范围之间切换,但确保了在焦点返回到焦点范围时,焦点范围中的焦点元素再次获得键盘焦点。

一个应用程序中可以有多个具有逻辑焦点的元素,但在一个特定的焦点范围中只能有一个具有逻辑焦点的元素。

具有键盘焦点的元素还具有它所属的焦点范围的逻辑焦点。

在可扩展应用程序标记语言 (XAML) 中,可以通过将 FocusManager 附加属性 IsFocusScope 设置为 true,将元素转变为焦点范围。 在代码中,可以通过调用 SetIsFocusScope 将元素转变为焦点范围。

下面的示例通过设置 IsFocusScope 附加属性将 StackPanel 转变为焦点范围。

<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>
 
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

GetFocusScope 返回指定元素的焦点范围。

WPF 中默认情况下即为焦点范围的类有 WindowMenuItemToolBarContextMenu

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 属性 TabNavigationControlTabNavigationDirectionalNavigation 来更改导航容器的导航行为。 这些属性是 KeyboardNavigationMode 类型,可能值有 ContinueLocalContainedCycleOnce 以及 None。 默认值是 Continue,这意味着元素不是导航容器。

下面的示例创建包含许多 MenuItem 对象的 MenuMenuTabNavigation 附加属性设置为 Cycle。 当使用 Tab 键在 Menu 中改变焦点时,焦点将从每个元素上移过,当到达最后一个元素后会返回第一个元素。

 
 

<Menu KeyboardNavigation.TabNavigation="Cycle">
  <MenuItem Header="Menu Item 1" />
  <MenuItem Header="Menu Item 2" />
  <MenuItem Header="Menu Item 3" />
  <MenuItem Header="Menu Item 4" />
</Menu>

 
 

Menu navigationMenu = new Menu();
MenuItem item1 = new MenuItem();
MenuItem item2 = new MenuItem();
MenuItem item3 = new MenuItem();
MenuItem item4 = new MenuItem();

navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);

KeyboardNavigation.SetTabNavigation(navigationMenu,   KeyboardNavigationMode.Cycle);

以编程方式定位焦点


处理焦点的其他 API 有 MoveFocusPredictFocus

MoveFocus 将焦点移到应用程序中的下一个元素。 TraversalRequest 用于指定方向。 传递给 MoveFocusFocusNavigationDirection 指定焦点可以移动的不同方向,如 FirstLastUpDown

下面的示例使用 MoveFocus 来改变焦点元素。 有关此示例的完整源代码,请参见以编程方式操作焦点示例

 
 

// 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);
}

PredictFocus 返回当要改变焦点时将接收焦点的对象。 当前,PredictFocus 仅支持 UpDownLeft 以及 Right

焦点事件


与键盘焦点相关的事件有 PreviewGotKeyboardFocusGotKeyboardFocusPreviewLostKeyboardFocus 以及 LostKeyboardFocus。 这些事件定义为 Keyboard 类的附加事件,但更便于作为基元素类上的等效路由事件来访问。 有关事件的更多信息,请参见路由事件概述

当元素获取键盘焦点时,会引发 GotKeyboardFocus。当元素失去键盘焦点时,会引发 LostKeyboardFocus。 如果处理了 PreviewGotKeyboardFocus 事件或 PreviewLostKeyboardFocusEvent 事件,并且 Handled 设置为 true,则焦点将不会改变。

下面的示例将 GotKeyboardFocusLostKeyboardFocus 事件处理程序附加到 TextBox

 
 

<Border BorderBrush="Black" BorderThickness="1"
        Width="200" Height="100" Margin="5">
  <StackPanel>
    <Label HorizontalAlignment="Center" Content="Type Text In This TextBox" />
    <TextBox Width="175"
             Height="50"
             Margin="5"
             TextWrapping="Wrap"
             HorizontalAlignment="Center"
             VerticalScrollBarVisibility="Auto"
             GotKeyboardFocus="TextBoxGotKeyboardFocus"
             LostKeyboardFocus="TextBoxLostKeyboardFocus"
             KeyDown="SourceTextKeyDown"/>
  </StackPanel>
</Border>

TextBox 获取键盘焦点时,TextBoxBackground 属性会改为 LightBlue

 
 

private void TextBoxGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

if (source != null)
    {
        // Change the TextBox color when it obtains focus.
        source.Background = Brushes.LightBlue;

// Clear the TextBox.
        source.Clear();
    }
}

TextBox 失去键盘焦点时,TextBoxBackground 属性会重新改为 white。

 
 

private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
    TextBox source = e.Source as TextBox;

if (source != null)
    {
        // Change the TextBox color when it loses focus.
        source.Background = Brushes.White;

// Set the  hit counter back to zero and updates the display.
        this.ResetCounter();
    }
}

与逻辑焦点有关的事件有 GotFocusLostFocus。 这些事件在 FocusManager 上定义为附加事件,但 FocusManager 不公开 CLR 事件包装。UIElementContentElement 可以更方便地公开这些事件。

文章来源   http://zwkufo.blog.163.com/blog/static/2588251201042014725122/

[转]WPF焦点概述的更多相关文章

  1. 微软原文翻译:适用于.Net Core的WPF数据绑定概述

    原文链接,大部分是机器翻译,仅做了小部分修改.英.中文对照,看不懂的看英文. Data binding overview in WPF 2019/09/19 Data binding in Windo ...

  2. wpf动画概述

    http://msdn.microsoft.com/zh-cn/library/vstudio/ms752312(v=vs.100).aspx Windows Presentation Foundat ...

  3. WPF学习概述

    引言 在桌面开发领域,虽然在某些领域,基于electron的跨平台方案能够为我们带来某些便利,但是由于WPF技术能够更好的运用Direct3D带来的性能提升.以及海量Windows操作系统和硬件资源的 ...

  4. WPF 一 概述

    创建一个项目吧 菜单>文件>新建>项目 看一看目录结构 WPF应用程序”会在“引用”里面自动添加下图中所示的 PresentationCore.PresentationFramewo ...

  5. [WPF 自定义控件]让Form在加载后自动获得焦点

    1. 需求 加载后让第一个输入框或者焦点是个很基本的功能,典型的如"登录"对话框.一般来说"登录"对话框加载后"用户名"应该马上获得焦点,用 ...

  6. [WPF自定义控件库] 让Form在加载后自动获得焦点

    原文:[WPF自定义控件库] 让Form在加载后自动获得焦点 1. 需求 加载后让第一个输入框或者焦点是个很基本的功能,典型的如"登录"对话框.一般来说"登录" ...

  7. WPF 程序如何跨窗口/跨进程设置控件焦点

    原文:WPF 程序如何跨窗口/跨进程设置控件焦点 WPF 程序提供了 Focus 方法和 TraversalRequest 来在 WPF 焦点范围内转移焦点.但如果 WPF 窗口中嵌入了其他框架的 U ...

  8. WPF 中的形状和基本绘图概述

    本主题概述如何使用 Shape 对象绘图. Shape 是一种允许您在屏幕中绘制形状的 UIElement 类型. 由于它们是 UI 元素,因此 Shape 对象可以在 Panel 元素和大多数控件中 ...

  9. WPF从入门到放弃系列第一章 初识WPF

    什么是WPF WPF(Windows Presentation Foundation)是微软推出的基于Windows Vista的用户界面框架,属于.NET Framework 3.0的一部分.它提供 ...

随机推荐

  1. The Battle of Chibi

    The Battle of Chibi 给出一段长度为n的序列\(\{a_i\}\),求其中长度为m的严格上升子序列个数\(mod\ 10^9+7\),\(n\leq 10^3\). 解 不难想到设\ ...

  2. Spring知识点整理

    1.bean什么时候被实例化 第一:如果你使用BeanFactory作为Spring Bean的工厂类,则所有的bean都是在第一次使用该Bean的时候实例化第二:如果你使用ApplicationCo ...

  3. 阿里云 Aliplayer高级功能介绍(三):多字幕

    基本介绍 国际化场景下面,播放器支持多字幕,可以有效解决视频的传播障碍难题,该功能适用于视频内容在全球范围内推广,阿里云的媒体处理服务提供接口可以生成多字幕,现在先看一下具体的效果: WebVTT格式 ...

  4. 最大流Dinic算法的一些优化 [网络流][最大流]

    明天省夏要讲网络流啦!晚上翻出自己的模板发现是蓝书模板QwQ..拿出以前的提交代码(AC过的?) 曾经的提交记录 在luogu上重新提交一遍,结果gg...OVO 没有去除多余的inline 去除了多 ...

  5. 2017/7/26 SCJP英语学习

    1 Declarations and Access Control ............... 1 Java Refresher . . . . . . . . . . . . . . . . . ...

  6. Mybatis功能架构及执行流程

    原文地址:http://blog.51cto.com/12222886/2052647 一.功能架构设计 功能架构讲解: 我们把Mybatis的功能架构分为三层: (1) API接口层:提供给外部使用 ...

  7. niginx相关命令及代理配置

    安装 in mac https://www.cnblogs.com/meng1314-shuai/p/8335140.html Nginx相关命令 mac下启动: 通过brew 安装install 后 ...

  8. 通过apiservice反向代理访问service

    第一种:NodePort类型 type: NodePort ports: - port: 80 targetPort: 80 nodePort: 30008 ​ 第二种:ClusterIP类型 typ ...

  9. 结合sessionStorage解决vuex页面刷新数据丢失的问题

    将需要保存在vuex中的数据同时保存在sessionStorage中即可: import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); ...

  10. 服务器访问数据库表mysql

    服务器的MySQL配置就不说了,直接说一些用到的基础命令 登陆 show databases; use 数据库: show tables; 执行sql即可: 一定要有分号 select * from ...