添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

WPF三大基础元素:键盘、鼠标与焦点

键盘类与事件处理

  • WPF框架 中内置了 System.Input.Keyboard 基础 键盘类 ,该类提供了丰富的键盘相关功能,包括描述 键盘状态 的属性、 处理键盘操作 的方法以及一系列事件。这些键盘事件不仅直接由 Keyboard类 提供,还通过 UIElement等XAML基元素类 向外传递。
  • 处理键盘输入 时,常用的 两个事件组 是:
  1. KeyDown和PreviewKeyDown事件 :当 键盘键 按下 时,这两个 事件 会被 触发 KeyDown事件 属于 冒泡路由事件 ,这意味着它会从 底层元素向上传播 到包含它的 元素 。而 PreviewKeyDown事件 隧道路由事件 ,它会将事件 沿着逻辑树向上传递 ,直到它被处理或路由到 根元素
  2. KeyUp和PreviewKeyUp事件 :当 键盘键 释放 时,这两个 事件 会被 触发 KeyUp事件 同样是 冒泡路由事件 ,而 PreviewKeyUp事件 则是 隧道路由事件
  • 如果要使某个 UI元素 能够 接收并响应 键盘输入,首要条件是该元素必须具有 焦点 。大部分 UIElement的派生类 默认 都可获取 焦点 ,但是像 StackPanel和Canvas 这类 Panel类 ,默认情况下其 Focusable 属性被设置为 false ,因此 不能 直接获取 焦点 。若需此类元素能响应键盘输入,则需要 显式 将其 Focusable 属性设为 true
  • 下面写个以 PreviewKeyDown 为例子:
<Window x:Class="WpfKeyboardEventsApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfKeyboardEventsApp"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"  Focusable="True" PreviewKeyDown="Window_PreviewKeyDown"><Grid><!--添加TextBlock用来显示键盘输入显示效果--><TextBlock x:Name="myTextBlock" Text="这里演示“静音”、“增大音量”、“减小音量”这三个快捷键" Foreground="White" Background="Green" FontSize="16"  Height="33" Padding="10,6"  HorizontalAlignment="Center"></TextBlock></Grid>
</Window>
using System.Windows;
using System.Windows.Input;namespace WpfKeyboardEventsApp
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Window_PreviewKeyDown(object sender, KeyEventArgs e){if (e.Key == Key.VolumeMute){// 按下“静音”键myTextBlock.Text = "按下“静音”键";e.Handled = true;}else if (e.Key == Key.VolumeUp){// 按下“增大音量”键myTextBlock.Text = "按下“增大音量”键";e.Handled = true;}else if (e.Key == Key.VolumeDown){// 按下“减小音量”键myTextBlock.Text = "按下“减小音量”键";e.Handled = true;}}}

上述代码,当用户在窗口中按下键盘按键时,将调用名为Window_PreviewKeyDown的事件处理程序来处理按键事件。效果如下:
PreviewKeyDown

鼠标类与鼠标事件处理

  • WPF框架内建的System.Input.Mouse类为开发人员提供了丰富的鼠标相关功能,涵盖了关于鼠标状态的各种事件、方法及属性。类似于键盘事件的处理方式,Mouse类所包含的这些事件同样通过UIElement和其他XAML基元素类传递给应用程序。
  • 鼠标事件主要分为以下几个类别,每个类别都有对应的冒泡路由事件和隧道路由事件对:
  1. MouseDown和PreviewMouseDown事件:当用户按下鼠标按钮时触发,用于响应鼠标键按下动作。
  2. MouseUp和PreviewMouseUp事件:在用户释放鼠标按钮时发生,用于处理鼠标键抬起的动作。
  3. MouseEnter和PreviewMouseEnter事件:当鼠标光标进入控件区域时通知,标志着鼠标从外部移入控件。
  4. MouseLeave和PreviewMouseLeave事件:当鼠标离开控件边界时激活,表明鼠标从控件内部移至外部区域。
  5. MouseMove和PreviewMouseMove事件:随着鼠标在控件范围内移动而持续触发,可用于实时追踪鼠标的移动轨迹。
    要对于获取精确的鼠标位置,可通过调用Mouse类的GetPosition静态方法,该方法接受一个UIElement参数,返回的是相对于指定控件坐标系内的鼠标位置坐标,从而使得开发者能够根据具体控件上下文来捕获并处理鼠标的位置变化。
  • 下面写个例子:
<Grid><Grid.RowDefinitions><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><!--添加一个矩形来演示鼠标的相关操作--><Rectangle x:Name="myRectangle" Grid.Row="0"  Canvas.Left="246" Canvas.Top="46" Height="118"  Stroke="Black"  Width="200" Fill="White"MouseEnter="myRectangle_MouseEnter" MouseLeave="myRectangle_MouseLeave" MouseMove="myRectangle_MouseMove" MouseDown="myRectangle_MouseDown"MouseWheel="myRectangle_MouseWheel"></Rectangle><!--添加TextBlock来显示相关提示--><TextBlock x:Name="myTextBlock" Grid.Row="1" HorizontalAlignment="Center" FontSize="16" Foreground="Green" Text="鼠标滚动会改变矩形的宽度"></TextBlock></Grid>
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;namespace WpfKeyboardEventsApp
{/// <summary>/// MouseWindow.xaml 的交互逻辑/// </summary>public partial class MouseWindow : Window{public MouseWindow(){InitializeComponent();}private void myRectangle_MouseEnter(object sender, MouseEventArgs e){// 鼠标进入控件时,控件的颜色为蓝色myRectangle.Fill = new SolidColorBrush(Colors.Blue);}private void myRectangle_MouseLeave(object sender, MouseEventArgs e){// 鼠标离开控件时,控件的颜色为白色myRectangle.Fill = new SolidColorBrush(Colors.White);}private void myRectangle_MouseMove(object sender, MouseEventArgs e){// 获取基于Rectangle的鼠标的坐标Point pointBaseRectangle = Mouse.GetPosition(myRectangle);myTextBlock.Text = $"鼠标位置矩形的底部为 ({pointBaseRectangle.X},{pointBaseRectangle.Y})";myTextBlock.Text += "\r\n";// 获取基于窗体的鼠标的坐标Point pointBaseWindow = Mouse.GetPosition(this);myTextBlock.Text += $"鼠标位置基于窗口为 ({pointBaseWindow.X},{pointBaseWindow.Y})";}private void myRectangle_MouseDown(object sender, MouseButtonEventArgs e){// 获取点出的鼠标的按钮,是左边还是右边MouseButton button = e.ChangedButton;myTextBlock.Text += "\r\n";myTextBlock.Text += $"鼠标按键是{button.ToString()}";}private void myRectangle_MouseWheel(object sender, MouseWheelEventArgs e){if (e.Delta > 0){// 如果向上推动滚轮,图形的宽度增加myRectangle.Width++;}if (e.Delta < 0){// 如果向下推动滚轮,图形的宽度减小myRectangle.Width--;}}}

上述代码,包含一个矩形和一个文本块。当用户在矩形上执行鼠标操作时,将调用相应的事件处理程序来处理这些操作。文本块用于显示相关提示信息,效果图如下:
Mouse描述

WPF中的焦点处理机制

  • 在WPF应用程序中,焦点处理涉及到两个关键概念:键盘焦点和逻辑焦点。其中,键盘焦点特指当前接收键盘输入的元素,而逻辑焦点则是在特定焦点范围内的焦点元素。

1.键盘焦点

  • 是当前接受键盘输入的对象,整个桌面同一时间只能有一个元素拥有键盘焦点。在WPF中,若一个元素具有键盘焦点,其IsKeyboardFocused属性将被设置为true。通过Keyboard类的静态属性FocusedElement可以获取当前拥有键盘焦点的元素。
    若要使某个UI元素能够获取键盘焦点,需要确保该元素的Focusable属性和IsVisible属性均设为true。例如,默认情况下,Panel等基类的Focusable属性为false,因此需手动设置为true以允许此类元素获取焦点。
    用户可以通过交互操作(如按Tab键切换或点击元素)来改变键盘焦点。此外,还可以使用Keyboard.Focus(element)方法以编程方式尝试将键盘焦点赋予指定元素,但返回的结果可能是当前真正获得键盘焦点的元素,因为如果有其他因素阻止了请求,则结果可能与预期不符。
  • 下面来写个例子:
<StackPanel HorizontalAlignment="Center"><!--设置Focusable为True 表示可以用键盘获取到焦点--><TextBox x:Name="myTextBox" Focusable="True" Text="我是TextBox1" Margin="0,10"  GotKeyboardFocus="myTextBox_GotKeyboardFocus"/><TextBox x:Name="myTextBox2" Focusable="True" Text="我是TextBox2" Margin="0,10" GotKeyboardFocus="myTextBox_GotKeyboardFocus"/><TextBlock x:Name="myTextBlock" Text="我是一个提示,用来提示谁获取焦点获取焦点" Margin="0,10" Foreground="Red"/>
</StackPanel>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;namespace WpfKeyboardEventsApp
{/// <summary>/// FocusWindow.xaml 的交互逻辑/// </summary>public partial class FocusWindow : Window{public FocusWindow(){InitializeComponent();// 初始化设置myTextBox为焦点Keyboard.Focus(myTextBox);}private void myTextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e){myTextBlock.Text = $"{((TextBox)sender).Name} 获取了键盘焦点";}}

上述代码,包含两个输入框和一个文本宽,默认设置第一个输入框为焦点,利用Tab切换,文本显示对应的切换提示,效果图如下:
键盘焦点

2.逻辑焦点

  • 体现在FocusManager.FocusedElement上,它指的是在一个焦点范围内的焦点元素。当键盘焦点离开焦点范围时,尽管该元素失去了键盘焦点,但仍保留逻辑焦点。当键盘焦点重新回到焦点范围内时,该元素会再次获得键盘焦点,这使得键盘焦点能在多个焦点范围间切换,同时保证焦点返回时,焦点范围内的焦点元素能重获键盘焦点。
    -在一个应用程序中,可以存在多个拥有逻辑焦点的元素,但在单一焦点范围内仅有一个元素拥有逻辑焦点。可通过调用FocusManager.GetFocusScope(element)得到指定元素所在的焦点范围,而FocusManager.GetFocusedElement(scope)用于获取指定焦点范围内的焦点元素,FocusManager.SetFocusedElement(scope, element)则用来设置焦点范围内的焦点元素,通常用于设定初始焦点。
  • 下面来写个例子:
<StackPanel HorizontalAlignment="Center"><!--设置TabControl 下面的内容TextBox可以获取到键盘焦点--><TabControl><TabItem Header="Tab导航一"><TextBox x:Name="tab1TextBox" Text="我是Tab1的内容,我这里仅仅之作演示" Focusable="True" Foreground="Red"  Height="200"/></TabItem><TabItem Header="Tab导航二"><TextBox x:Name="tab2TextBox" Focusable="True" Text="我是Tab2的内容,我这里仅仅之作演示" Foreground="Blue"  Height="200"/></TabItem></TabControl>
</StackPanel>

上述代码,在一个具有多个TabItem的TabControl中,每个TabItem可以视为一个独立的焦点范围。当切换到另一个TabItem时,即使当前TabItem中的元素失去了键盘焦点,它仍保留逻辑焦点。若返回原来的TabItem,先前获得焦点的元素会重新获取键盘焦点,效果图如下:
逻辑焦点

3.键盘导航

  • 当用户按下导航键(如Tab、Shift+Tab、Ctrl+Tab组合键以及方向键)时,KeyboardNavigation类负责实现默认的键盘焦点导航行为。通过设置附加属性KeyboardNavigation.TabNavigation、ControlTabNavigation和DirectionalNavigation,可以自定义导航容器的导航策略,这些属性可取值包括Continue(继续导航。当键盘导航到达元素的末尾时,导航将继续到下一个元素)、Local(本地循环。当键盘导航到达元素的末尾时,导航将从头开始导航元素。)、Contained(包含循环。当键盘导航到达元素的末尾时,导航将从头开始导航元素,直到所有元素都被导航。)、Cycle(循环。当键盘导航到达元素的末尾时,导航将从头开始导航元素,直到所有元素都被导航。)、Once(一次。当键盘导航到达元素的末尾时,导航将停止。)和None(无。当键盘导航到达元素的末尾时,导航将不执行任何操作。),默认为Continue
  • 下面来写个例子:
<StackPanel HorizontalAlignment="Center"><!--设置按下Tab键时仅在其内部循环移动焦点,直到所有的都被导航停止--><ListBox KeyboardNavigation.TabNavigation="Contained"><ListBoxItem Content="我是ListBox选项1"/><ListBoxItem Content="我是ListBox选项2"/><ListBoxItem Content="我是ListBox选项3"/><ListBoxItem Content="我是ListBox选项4"/><ListBoxItem Content="我是ListBox选项5"/><ListBoxItem Content="我是ListBox选项6"/><ListBoxItem Content="我是ListBox选项7"/><ListBoxItem Content="我是ListBox选项8"/></ListBox>
</StackPanel>

上述代码,ListBox在按下Tab键时仅在其内部循环移动焦点,不跳转到其他控件上,到最后一个元素导航,效果图如下:
定义导航

4.焦点事件

  • 关于键盘焦点的事件包括PreviewGotKeyboardFocus、GotKeyboardFocus、PreviewLostKeyboardFocus以及LostKeyboardFocus。这些事件作为Keyboard类的附加事件,但在实际开发中更常作为基元素类上的路由事件使用。
    具体来说,当元素获取键盘焦点时触发GotKeyboardFocus事件;失去键盘焦点时引发LostKeyboardFocus事件。如果在预处理阶段即PreviewGotKeyboardFocus或 PreviewLostKeyboardFocus事件中设置了Handled为true,则焦点状态将不会发生改变。
  • 下面来写个例子:
<StackPanel HorizontalAlignment="Center"><!--设置TextBox添加三个事件--><TextBox x:Name="myTextBox" Focusable="True" PreviewGotKeyboardFocus="myTextBox_PreviewGotKeyboardFocus"  GotKeyboardFocus="myTextBox_GotKeyboardFocus"  LostKeyboardFocus="myTextBox_LostKeyboardFocus" Width="180" Margin="0,10"/><TextBox  Focusable="True" Text="我是用来测试焦点转移" Width="180" Margin="0,10"/><TextBlock x:Name="myTextBlock" Text="我是一个提示,用来提示焦点相关信息"  Foreground="Red" FontSize="16"/><Button Content="设置/取消阻止转移焦点" Click="Button_Click" Width="180"  Margin="0,30" Background="Green" Foreground="White" FontSize="16"></Button></StackPanel>
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;namespace WpfKeyboardEventsApp
{/// <summary>/// FocusWindow.xaml 的交互逻辑/// </summary>public partial class FocusWindow : Window{private bool disableFocus = false;  //禁止转移焦点public FocusWindow(){InitializeComponent();// 初始化设置myTextBox为焦点Keyboard.Focus(myTextBox);}private void myTextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e){//获得焦点//myTextBlock.Text = $"{((TextBox)sender).Name} 获取了键盘焦点";myTextBlock.Text = $"我获得焦点了";myTextBox.Background = Brushes.Yellow;}private void myTextBox_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e){//焦点转移时触发if (disableFocus){myTextBlock.Text = $"我焦点转移阻止了";e.Handled = true; // 阻止焦点转移}}private void myTextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e){//失去焦点myTextBlock.Text = $"我失去焦点了";myTextBox.Background = Brushes.White;}private void Button_Click(object sender, RoutedEventArgs e){disableFocus = !disableFocus;}}

上述代码,当TextBox获取或失去键盘焦点时,触发相应的事件,效果图如下:
焦点事件

公众号“点滴分享技术猿

关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: http://www.xdnf.cn/news/1030382.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

应用keras建立ANN模型.

介绍&#xff1a; Keras是一个开源的神经网络库&#xff0c;它基于Python语言&#xff0c;并能够在多个深度学习框架上运行&#xff0c;包括TensorFlow、Theano和CNTK。Keras提供了一种简洁而高层次的API&#xff0c;使得用户能够快速构建、训练和部署神经网络模型。 Keras的设…

三分钟教你入门规则引擎Drools

Drools是一款基于Java语言的开源的规则引擎&#xff0c;可以将复杂且多变的规则从硬编码中解放出来&#xff0c;以规则脚本的形式存放在文件或者特定的存储介质中(eg:数据库表)&#xff0c;使得业务规则的变更不需要修正项目代码&#xff0c;重启服务器就可以在线上环境立即生效…

第九节HarmonyOS 常用基础组件22-Marquee

1、描述 跑马灯组件&#xff0c;用于滚动展示一段单行文本&#xff0c;仅当文本内容宽度超过跑马灯组件宽度时滚动。 Marquee(value:{start:boolean, step?:number, loop?:number, fromStart?: boolean ,src:string}) 3、参数 参数名 参数类型 必填 描述 st…

力扣hot100 划分字母区间 贪心 思维 满注释版

Problem: 763. 划分字母区间 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 代码随想录 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) class Solution {public List<Integer> partitionLabels(String s){// 创建哈希…

基于腾讯云自然语言处理 NLP服务实现文本情感分析

文章目录 一、前言二、NLP 服务简介三、Python 调用腾讯云 NLP 服务 SDK 构建情感分析处理3.1 开通腾讯云 NLP 服务3.2 创建的腾讯云持久证书&#xff08;如果已创建请跳过&#xff09;3.2 在腾讯云服务器中安装 Git 工具以及 Python 环境3.3 安装 qcloudapi-sdk-python3.4 部署…

什么是美颜SDK?直播美颜SDK技术揭秘

美颜技术作为图像处理领域的一个重要分支&#xff0c;正在成为移动应用和直播行业的关键元素。而在这一领域&#xff0c;美颜SDK的应用愈发广泛&#xff0c;成为直播美颜工具的核心。 一、美颜SDK的基本概念 美颜SDK使开发者能够在其应用或平台中集成美颜功能。美颜SDK通常提供…

JAVA可变参数

题目引出&#xff1a;在以前我们是这样做的&#xff1a;帮我们要求和的数据写在数组内即可 public class Test01 {public static void main(String[] args) {int []arr{1,2,3,4,5,6,7,8,9,10};int sum getSum(arr);System.out.println(sum);}public static int getSum( int […

【每日一题】找出不同元素数目差数组

文章目录 Tag题目来源解题思路方法一&#xff1a;哈希集合 写在最后 Tag 【哈希集合】【数组】【2024-01-31】 题目来源 2670. 找出不同元素数目差数组 解题思路 方法一&#xff1a;哈希集合 使用哈希集合来存放数组中的元素&#xff0c;哈希集合可以实现去重功能。 …

备战蓝桥杯---数据结构与STL应用(优先队列的小细节)

很显然&#xff0c;我们先二分求X,对于验证&#xff0c;一开始我先想的是直接求每个的不足电量再除充电量后向上取整&#xff0c;然后判断与k的大小关系。事实上&#xff0c;如果让k很大&#xff0c;若有两只手机在下一刻多没电&#xff0c;显然上述方法得出的结论是错误的&amp…

【Pwn | CTF】BUUCTF test_your_nc1

天命&#xff1a;时隔两年&#xff0c;又杀回了pwn这里 拿到题目的提示&#xff0c;测试你的nc工具 这题直接连接就可以了&#xff0c;windows装了nc工具&#xff0c;直接耍 nc node5.buuoj.cn 28930 下面给一点nc命令的解释&#xff0c;文心一言得出来的 nc命令是一个用于网…

如何搭建一个成功的家装预约咨询小程序

微信小程序是一种在微信平台上运行的应用程序&#xff0c;为企业提供了一个快速、便捷的方式与用户进行交互和服务。开通微信家装预约咨询小程序店铺&#xff0c;可以帮助家装企业更好地与用户进行沟通和服务&#xff0c;提升用户体验和便捷度。下面我们就来详细介绍一下开通微…

如何配置 Podman 使用国内镜像源?

Podman 配置国内镜像源 什么是 Podman&#xff1f;Docker 与 Podman 区别修改 Podman 容器注册表配置国内的镜像源Podman Container Registries 修改步骤检查配置是否生效 Podman 容器存储总结 什么是 Podman&#xff1f; Podman 是一种符合 OCI 标准的容器管理工具&#xff0c…

【百度Apollo】探索自动驾驶:深入解析Apollo开放平台架构的博客指南

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

[工具探索]Safari 和 Google Chrome 浏览器内核差异

最近有些Vue3的项目&#xff0c;使用了safari进行测试环境搞开发&#xff0c;发现页面存在不同程序的页面乱码情况&#xff0c;反而google浏览器没问题&#xff0c;下面我们就对比下他们之间的差异点&#xff1a; 日常开发google chrome占多数&#xff1b;现在主流浏览器 Goog…

DMA+串口空闲中断实现RS485不定长数据接收和发送

目录 1、环境说明2、实现不定长数据接收需要做哪些事&#xff1f;2.1、数据的接收与缓存2.2、数据帧的结束判断2.3、数据帧的长度计算 3、RS485串口实现不定长数据发送4、代码实现结语&#xff1a; 1、环境说明 单片机型号;Cortex-M4架构&#xff0c;AT32F437 说明&#xff1a…

我们距离AGI还有多远

什么是AGI AGI&#xff08;人工通用智能&#xff09;是指能够像人类一样完成任何智能任务的人工智能系统。AGI的目标是创建一个全面智能的系统&#xff0c;可以解决广泛的问题并进行多种任务。这种系统能够在不同的环境中适应和学习&#xff0c;并且可以从不同的来源中获取信息…

Leetcode—807. 保持城市天际线【中等】

2024每日刷题&#xff08;一零四&#xff09; Leetcode—807. 保持城市天际线 实现代码