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

相关文章

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

Python中对FFmpeg封装开发库FFmpy详解

《Python中对FFmpeg封装开发库FFmpy详解》:本文主要介绍Python中对FFmpeg封装开发库FFmpy,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、FFmpy简介与安装1.1 FFmpy概述1.2 安装方法二、FFmpy核心类与方法2.1 FF

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

WinForms中主要控件的详细使用教程

《WinForms中主要控件的详细使用教程》WinForms(WindowsForms)是Microsoft提供的用于构建Windows桌面应用程序的框架,它提供了丰富的控件集合,可以满足各种UI设计... 目录一、基础控件1. Button (按钮)2. Label (标签)3. TextBox (文本框

使用WPF实现窗口抖动动画效果

《使用WPF实现窗口抖动动画效果》在用户界面设计中,适当的动画反馈可以提升用户体验,尤其是在错误提示、操作失败等场景下,窗口抖动作为一种常见且直观的视觉反馈方式,常用于提醒用户注意当前状态,本文将详细... 目录前言实现思路概述核心代码实现1、 获取目标窗口2、初始化基础位置值3、创建抖动动画4、动画完成后

一文详解如何在Vue3中封装API请求

《一文详解如何在Vue3中封装API请求》在现代前端开发中,API请求是不可避免的一部分,尤其是与后端交互时,下面我们来看看如何在Vue3项目中封装API请求,让你在实现功能时更加高效吧... 目录为什么要封装API请求1. vue 3项目结构2. 安装axIOS3. 创建API封装模块4. 封装API请求

双系统电脑中把Ubuntu装进外接移动固态硬盘的全过程

《双系统电脑中把Ubuntu装进外接移动固态硬盘的全过程》:本文主要介绍如何在Windows11系统中使用VMware17创建虚拟机,并在虚拟机中安装Ubuntu22.04桌面版或Ubunt... 目录一、首先win11中安装vmware17二、磁盘分区三、保存四、使用虚拟机进行系统安装五、遇见的错误和解决

使用FileChannel实现文件的复制和移动方式

《使用FileChannel实现文件的复制和移动方式》:本文主要介绍使用FileChannel实现文件的复制和移动方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录使用 FileChannel 实现文件复制代码解释使用 FileChannel 实现文件移动代码解释

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否