WPF 给任意控件通过按下移动抬起封装点击事件(转载)

2024-01-19 21:58

本文主要是介绍WPF 给任意控件通过按下移动抬起封装点击事件(转载),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

其实点击这个事件是可以通过按下移动和抬起三个事件封装出来的,本文提供给大家一个辅助的方法,方便给任意的控件附加点击事件

在开始前需要了解一些本文点击的定义,本文点击的定义就是在按下到抬起过程中,不会出现长距离的移动,也就是从点击到抬起的点都是在一定范围内的。同时可以设置一定的时间范围,超过一定时间就是长按了,而不是点击了

根据这个特点咱开始来进行一个简单的封装,在封装之前先告诉大家封装之后的使用方法,下面代码的 uiElement 是一个 UIElement 控件

        InputHelper.AttachMouseDownMoveUpToClick(uiElement, UIElement_OnClicked);private void UIElement_OnClicked(object sender, EventArgs e){}

实现 InputHelper 请看下面代码

/// <summary>
/// 输入层的帮助类
/// </summary>
public static class InputHelper
{/// <summary>/// 将 MouseDown MouseMove MouseUp 封装为点击事件/// </summary>/// <param name="element">要被附加的元素</param>/// <param name="clickEventHandler">点击的事件</param>/// <param name="dragStarted">因为拖动而结束点击时触发</param>public static void AttachMouseDownMoveUpToClick(UIElement element, EventHandler clickEventHandler,EventHandler dragStarted = null){var inputInfo = GetOrCreateInputInfo(element);inputInfo.ClickEventHandler += clickEventHandler;inputInfo.DragStarted += dragStarted;element.MouseDown -= Element_MouseDown;element.MouseDown += Element_MouseDown;element.MouseMove -= Element_MouseMove;element.MouseMove += Element_MouseMove;element.MouseUp -= Element_MouseUp;element.MouseUp += Element_MouseUp;element.LostMouseCapture -= Element_LostMouseCapture;element.LostMouseCapture += Element_LostMouseCapture;}/// <summary>/// 去掉对 <paramref name="element"/> 的点击时间的监听/// </summary>/// <param name="element"></param>/// <param name="clickEventHandler">点击的事件</param>/// <param name="dragStarted">因为拖动而结束点击时触发的事件</param>public static void DetachMouseDownMoveUpToClick(UIElement element, EventHandler clickEventHandler,EventHandler dragStarted = null){var inputInfo = GetInputInfo(element);if (inputInfo == null){return;}inputInfo.ClickEventHandler -= clickEventHandler;inputInfo.DragStarted -= dragStarted;if (inputInfo.IsEmpty()){element.ClearValue(InputInfoProperty);element.MouseDown -= Element_MouseDown;element.MouseMove -= Element_MouseMove;element.MouseUp -= Element_MouseUp;element.LostMouseCapture -= Element_LostMouseCapture;}}private static void Element_LostMouseCapture(object sender, MouseEventArgs e){var element = (UIElement) sender;GetInputInfo(element)?.LostCapture();}private static void Element_MouseUp(object sender, MouseButtonEventArgs e){var element = (UIElement) sender;GetInputInfo(element)?.Up(e.GetPosition(element));}private static void Element_MouseMove(object sender, MouseEventArgs e){var element = (UIElement) sender;GetInputInfo(element)?.Move(e.GetPosition(element));}private static void Element_MouseDown(object sender, MouseButtonEventArgs e){var element = (UIElement) sender;GetInputInfo(element)?.Down(e.GetPosition(element));}private static readonly DependencyProperty InputInfoProperty = DependencyProperty.RegisterAttached("InputInfo", typeof(InputInfo), typeof(InputHelper), new PropertyMetadata(default(InputInfo)));private static InputInfo GetOrCreateInputInfo(UIElement element){var inputInfo = GetInputInfo(element);if (inputInfo == null){inputInfo = new InputInfo();SetInputInfo(element, inputInfo);}return inputInfo;}private static void SetInputInfo(DependencyObject element, InputInfo value){element.SetValue(InputInfoProperty, value);}private static InputInfo GetInputInfo(DependencyObject element){return (InputInfo) element.GetValue(InputInfoProperty);}private class InputInfo{public void Down(Point position){_downedPosition = position;_downedTime = DateTime.Now;_isClick = true;}public void Move(Point position){if (!_isClick) return;if ((position - _downedPosition).LengthSquared > ToleranceSquared){_isClick = false;DragStarted?.Invoke(null, EventArgs.Empty);}}public void Up(Point position){_isClick = _isClick&& (position - _downedPosition).LengthSquared <= ToleranceSquared&& DateTime.Now - _downedTime < ClickDuringTime;if (!_isClick) return;ClickEventHandler?.Invoke(null, EventArgs.Empty);_isClick = false;}public void LostCapture(){_isClick = false;}public double ToleranceSquared { set; get; } = 0.01;public TimeSpan ClickDuringTime { set; get; } = TimeSpan.MaxValue;public event EventHandler ClickEventHandler;public event EventHandler DragStarted;public bool IsEmpty() => ClickEventHandler is null && DragStarted is null;private Point _downedPosition;private DateTime _downedTime;private bool _isClick;}
}

当前这个类还有什么不足?没有提供外面可以设置点击的范围,也就是从按下开始可以移动的范围的值,以及运行点击的时间。从上面代码可以看到写的是 TimeSpan.MaxValue 也就是没有分开点击和长按的设置

另外方法里面还添加一个可选的委托是点击变拖动的事件,这个事件用来了解当前本来是点击的,但是点击的时候移动的距离判断为拖动

这个封装的方法没有用到什么框架里面的功能,因此换个框架,如 UWP 按照这个思路修改一点代码应该也可以做出来

我搭建了自己的博客 https://blog.lindexi.com/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入

如有不方便在博客评论的问题,可以加我 QQ 2844808902 交流

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

原文链接:https://blog.csdn.net/lindexi_gd/article/details/106789317?utm_medium=distribute.pc_feed.none-task-blog-alirecmd-8.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-alirecmd-8.nonecase&request_id=

这篇关于WPF 给任意控件通过按下移动抬起封装点击事件(转载)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/623819

相关文章

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

我在移动打工的日志

客户:给我搞一下录音 我:不会。不在服务范围。 客户:是不想吧 我:笑嘻嘻(气笑) 客户:小姑娘明明会,却欺负老人 我:笑嘻嘻 客户:那我交话费 我:手机号 客户:给我搞录音 我:不会。不懂。没搞过。 客户:那我交话费 我:手机号。这是电信的啊!!我这是中国移动!! 客户:我不管,我要充话费,充话费是你们的 我:可是这是移动!!中国移动!! 客户:我这是手机号 我:那又如何,这是移动!你是电信!!

JavaSE——封装、继承和多态

1. 封装 1.1 概念      面向对象程序三大特性:封装、继承、多态 。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节 。     比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器, USB 插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU 、显卡、内存等一些硬件元件。

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物,今天我们实现一下人物实现移动和跳起,依次点击,我们准备创建一个C#文件 创建好我们点击进去,就会跳转到我们的Vision Studio,然后输入这些代码 using UnityEngine;public class Move : MonoBehaviour // 定义一个名为Move的类,继承自MonoBehaviour{private Rigidbo

lvgl8.3.6 控件垂直布局 label控件在image控件的下方显示

在使用 LVGL 8.3.6 创建一个垂直布局,其中 label 控件位于 image 控件下方,你可以使用 lv_obj_set_flex_flow 来设置布局为垂直,并确保 label 控件在 image 控件后添加。这里是如何步骤性地实现它的一个基本示例: 创建父容器:首先创建一个容器对象,该对象将作为布局的基础。设置容器为垂直布局:使用 lv_obj_set_flex_flow 设置容器

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

简单的角色响应鼠标而移动

actor类 //处理移动距离,核心是找到角色坐标在世界坐标的向量的投影(x,y,z),然后在世界坐标中合成,此CC是在地面行走,所以Y轴投影始终置为0; using UnityEngine; using System.Collections; public class actor : MonoBehaviour { public float speed=0.1f; CharacterCo

C# 防止按钮botton重复“点击”的方法

在使用C#的按钮控件的时候,经常我们想如果出现了多次点击的时候只让其在执行的时候只响应一次。这个时候很多人可能会想到使用Enable=false, 但是实际情况是还是会被多次触发,因为C#采用的是消息队列机制,这个时候我们只需要在Enable = true 之前加一句 Application.DoEvents();就能达到防止重复点击的问题。 private void btnGenerateSh