最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。

实现了一个支持长短按得按钮组件,单击可以触发Click事件,长按可以触发LongPressed事件,长按松开时触发LongClick事件。源码请自取:Github

长按阈值属性的建立

为了方便在xaml中使用,我们先配置一个DependencyProperty叫做LongPressTime来作为界定长按的阈值

public class LongPressButtonEx : Button
{
public static readonly DependencyProperty LongPressTimeProperty
= DependencyProperty.Register("LongPressTime", typeof(int),
typeof(LongPressButtonEx), new PropertyMetadata(500)); public int LongPressTime
{
set => SetValue(LongPressTimeProperty, value);
get => (int)GetValue(LongPressTimeProperty);
}
}

定义完成后可以在Xaml设计器中使用LongPressTime这个拓展属性

<Window x:Class="LongPressButton.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:LongPressButton"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:LongPressButtonEx Width="96" Height="48" LongPressTime="200">
Button
</local:LongPressButtonEx>
</Grid>
</Window>

长按的定时器判定方法

C#中的4种定时器,在WPF中需要使用Dispater Timer

定义一个DispatcherTimer来监控是否按下达到了长按

private DispatcherTimer _pressDispatcherTimer;

private void OnDispatcherTimeOut(object sender, EventArgs e)
{
_pressDispatcherTimer?.Stop();
Debug.WriteLine($"Timeout {LongPressTime}");
} protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
Debug.WriteLine("Button: Mouse down.");
if (_pressDispatcherTimer == null)
{
_pressDispatcherTimer = new DispatcherTimer();
_pressDispatcherTimer.Tick += OnDispatcherTimeOut;
_pressDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, LongPressTime);
_pressDispatcherTimer.Start();
Debug.WriteLine("Button: Timer started");
}
} protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
Debug.WriteLine("Button: Mouse up.");
_pressDispatcherTimer?.Stop();
_pressDispatcherTimer = null;
}

现在分别点击和长按按钮可以看到调试输出

...
# 点击
Button: Mouse down.
Button: Timer started
Button: Mouse up.
# 长按
Button: Mouse down.
Button: Timer started
Timeout 200
Button: Mouse up.

实现长按事件的定义

现在作为一个自定义控件,我们需要在长按后发出一个RoutedEvent,并修改部分之前的代码抛出事件

/// <summary>
/// LongPress Routed Event
/// </summary>
public static readonly RoutedEvent LongPressEvent
= EventManager.RegisterRoutedEvent("LongPress",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(LongPressButtonEx)); public event RoutedEventHandler LongPress
{
add => AddHandler(LongPressEvent, value);
remove => RemoveHandler(LongPressEvent, value);
} private void OnDispatcherTimeOut(object sender, EventArgs e)
{
_pressDispatcherTimer?.Stop();
Debug.WriteLine($"Timeout {LongPressTime}");
RaiseEvent(new RoutedEventArgs(LongPressEvent)); // raise the long press event
}

回到窗体的代码中,添加事件的响应

<local:LongPressButtonEx Height="48" Width="256" LongPressTime="200"
LongPress="LongPressButtonEx_LongPress"
Click="LongPressButtonEx_Click">
Click or Long Press Me!
</local:LongPressButtonEx>

C#代码如下,长按按钮会显示Long Pressed,单击会是Click

private void LongPressButtonEx_LongPress(object sender, RoutedEventArgs e)
{
if (sender is LongPressButtonEx btn)
{
btn.Content = "Long Pressed";
}
} private void LongPressButtonEx_Click(object sender, RoutedEventArgs e)
{
if (sender is LongPressButtonEx btn)
{
btn.Content = "Clicked";
}
}

发现ClickLongPress都可以响应,但是当松开按钮时又变成了Click,原因是鼠标松开时响应了默认的Click事件

现在对按钮控件默认的OnClick函数稍作修改,可以让Click也不出问题

/// <summary>
/// DependencyProperty for IsLongPress
/// </summary>
public static readonly DependencyProperty IsLongPressProperty
= DependencyProperty.Register("IsLongPress", typeof(bool),
typeof(LongPressButtonEx), new PropertyMetadata(false)); public bool IsLongPress
{
set => SetValue(IsLongPressProperty, value);
get => (bool)GetValue(IsLongPressProperty);
} private void OnDispatcherTimeOut(object sender, EventArgs e)
{
IsLongPress = true;
_pressDispatcherTimer?.Stop();
Debug.WriteLine($"Timeout {LongPressTime}");
RaiseEvent(new RoutedEventArgs(LongPressEvent)); // raise the long press event
} protected override void OnClick()
{
if (!IsLongPress)
{
base.OnClick();
}
else
{
RaiseEvent(new RoutedEventArgs(LongPressReleaseEvent)); // raise the long press event
IsLongPress = false;
}
}

之后再进行点击操作,我们就可以看到符合预期的结果

长按+Style按钮的展示效果

外观Style自定义见这篇文章:WPF自定义按钮外形

参考链接

UIElement.MouseLeftButtonDown Event

用户控件自定义 DependencyProperty 属性使用教程

WPF 中 DispatcherTimer 计时器

如何:创建自定义路由事件

WPF 自定义带自定义参数路由事件

Use WPF Style in another assemble

Simple WPF: WPF 实现按钮的长按,短按功能的更多相关文章

  1. WPF实现Twitter按钮效果

    最近上网看到这个CSS3实现的Twitter按钮,感觉很漂亮,于是想用WPF来实现下. 实现这个效果,参考了CSS3 原文地址:http://www.html5tricks.com/css3-twit ...

  2. WPF 带清除按钮的文字框SearchTextBox

    原文:WPF 带清除按钮的文字框SearchTextBox 基于TextBox的带清除按钮的搜索框 样式部分: <!--带清除按钮文字框--> <Style TargetType=& ...

  3. WPF实现Twitter按钮效果(转)

    最近上网看到这个CSS3实现的Twitter按钮,感觉很漂亮,于是想用WPF来实现下. 实现这个效果,参考了CSS3 原文地址:http://www.html5tricks.com/css3-twit ...

  4. 在VS2005中设置WPF中自定义按钮的事件

    原文:在VS2005中设置WPF中自定义按钮的事件 上篇讲了如何在Blend中绘制圆角矩形(http://blog.csdn.net/johnsuna/archive/2007/08/13/17407 ...

  5. [原译]一步步教你制作WPF圆形玻璃按钮

    原文:[原译]一步步教你制作WPF圆形玻璃按钮 图1 1.介绍 从我开始使用vista的时候,我就非常喜欢它的圆形玻璃按钮.WPF最好的一个方面就是允许自定义任何控件的样式.用了一段时间的Micros ...

  6. WPF中使用AxisAngleRotation3D实现CAD的2D旋转功能

    原文:WPF中使用AxisAngleRotation3D实现CAD的2D旋转功能       对于CAD图形来说,3D旋转比较常用,具体实现方法在上篇文章<WPF中3D旋转的实现 >中做了 ...

  7. nginx 代理tcp长连接短连接配置

    https://blog.csdn.net/tayinyinyueyue/article/details/78932697 nginx使用ngx_stream_core_module模块代理tcp长连 ...

  8. 长连接 短连接 RST报文

    https://baike.baidu.com/item/短连接 短连接(short connnection)是相对于长连接而言的概念,指的是在数据传送过程中,只在需要发送数据时,才去建立一个连接,数 ...

  9. WPF学习笔记(2)——动画效果按钮变长

    说明(2017-6-12 11:26:48): 1. 视频教程里是把一个按钮点击一下,慢慢变长: 注意几个方面: (1)RoutedEvent="Button.Click",这里面 ...

  10. WPF datagrid 列按钮使用

    原文:WPF中使用DataGrid时操作列按钮问题     <DataGrid x:Name="datagrid" AutoGenerateColumns="Fal ...

随机推荐

  1. Nginx在Windows 10、Ubuntu16.04、Centos7下的安装

    目录 一. Windows 10 安装nginx 二. Ubuntu16.04 安装apt nginx 三. Centos7 yum安装nginx 四. ubuntu/centos编译安装nginx ...

  2. mybatisplus 中查询的实体对应的表名是动态的解决方案

    开发中遇到需要查询一些表里的数据,这些数据按照一定的规则存放在不同的数据库表里,例如表名是table_name+月份  table_name_2024_05,table_name_2024_04这样, ...

  3. 机器学习策略篇:详解为什么是人的表现?(Why human-level performance?)

    为什么是人的表现? 在过去的几年里,更多的机器学习团队一直在讨论如何比较机器学习系统和人类的表现,为什么呢? 认为有两个主要原因,首先是因为深度学习系统的进步,机器学习算法突然变得更好了.在许多机器学 ...

  4. AI 一键生成高清短视频,视频 UP 主们卷起来...

    现在短视频越来越火,据统计,2023年全球短视频用户数量已达 10 亿,预计到2027年将突破 24 亿.对于产品展示和用户营销来说,短视频已经成为重要阵地,不管你喜不喜欢它,你都得面对它,学会使用它 ...

  5. 深入学习Semantic Kernel:创建和配置prompts functions

    引言 上一章我们熟悉了一下 Semantic Kernel 的理论知识,Kernel 创建以及简单的Sample熟悉了一下 SK 的基本使用.在Semantic Kernel中的 kernel fun ...

  6. 模拟重装Kubernetes(k8s)集群:删除k8s集群然后重装

    目录 一.系统环境 二.前言 三.重装Kubernetes集群 3.1 环境介绍 3.2 删除k8s所有节点(node) 3.3 kubeadm初始化 3.4 添加worker节点到k8s集群 3.5 ...

  7. PyQGIS二次开发指南

    当你的数据处理使用的是Python语言,而你的导师又让你开发界面,那么PyQGIS二次开发指南是你必读的圣经.QGIS支持Python语言进行二次开发,你将学会如何使用Qt Designer进行界面设 ...

  8. pymysql的基本操作

    1.Python3连接MySQL import pymysql pymysql.connect(host='localhost',user='root',password='1',database=' ...

  9. 二叉树的遍历(BFS、DFS)

    二叉树的遍历(BFS.DFS) 本文分为以下部分: BFS(广度优先搜索) DFS(深度优先搜索) 先序遍历 中序遍历 后序遍历 总结 BFS(广度优先搜索) 广度优先搜索[^1](英语:Breadt ...

  10. CSP-S2021 游记

    那天是惊蛰 满天花瓣 就像现在 我看清了无池里的那个人 前言 终于是开了 游记 的坑(期盼已久!) 虽然参加过 CSP-J2019 ,CSP-S2020 以及 NOIP2020 ,但是都没有写过游记( ...