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. Altera FPGA– Bit Slip

    通过在接收端加延时,在延时间隙插入'0'或'1',以使最终接收和期望数据一致. BitSlip操作要注意几点: 1,BitSlip操作在rx_bitslip的上升沿即开始: 2,BitSlip操作开始 ...

  2. [JZOJ6340] 【NOIP2019模拟2019.9.4】B

    题目 题目大意 给你个非负整数数列\(a\),每次等概率选择大于零的\(a_i\),使其减\(1\). 问\(a_1\)被减到\(0\)的时候期望经过多少次操作. 思考历程 对于这题的暴力做法,显然可 ...

  3. HDU5377

    题意:给sum,m组询问,每组x,y求\(x^t=y\mod p,p|sum\),p是素数,求最小的t 题解:先处理sum的所有质因子p,求出p的原根rt,\(rt^a=x\mod p,rt^b=y\ ...

  4. Vue+Iview+Node 项目结构和配置

    1.项目调整后的目录 api:数据接口定义 assets:静态文件 components:组件  config:项目相关配置  driective:指令   router:路由   store:状态管 ...

  5. spss进行判别分析步骤_spss判别分析结果解释_spss判别分析案例详解

    spss进行判别分析步骤_spss判别分析结果解释_spss判别分析案例详解 1.Discriminant Analysis判别分析主对话框 如图 1-1 所示 图 1-1 Discriminant ...

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

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

  7. js 删除数组中指定值

    var arr = ['1','2'];delete('1'); function delete(i){ var index = arr.indexOf(i); arr.splice(index, 1 ...

  8. php 例子

    图片上传 uploadify(flash版是免费的) 12个最好的 HTML5 jQuery 文件上传脚本 20款最好的jQuery文件上传插件

  9. tensorflow识别验证码(2)-tensorflow 编写CNN 识别验证码

    1. 导入依赖包 #coding:utf-8 from gen_captcha import gen_captcha_text_and_image from gen_captcha import nu ...

  10. loj2513 治疗之雨

    题意:你的英雄一开始血量为p,你还有m个队友,血量无穷.血量上限为n,下限为0.如果血量满了就不能加血.每次启动操作,随机给m+1个英雄加1点血,然后等概率随机k次每次对于英雄扣1点血.求期望操作几次 ...