Simple WPF: WPF 实现按钮的长按,短按功能

  • Simple WPF: WPF 实现按钮的长按,短按功能已关闭评论
  • 46 次浏览
  • A+
所属分类:.NET技术
摘要

最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。实现了一个支持长短按得按钮组件,单击可以触发Click事件,长按可以触发LongPressed事件,长按松开时触发LongClick事件。源码请自取:Github

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

实现了一个支持长短按得按钮组件,单击可以触发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";     } } 

Simple WPF: WPF 实现按钮的长按,短按功能

发现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;     } } 

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

Simple WPF: WPF 实现按钮的长按,短按功能

长按+Style按钮的展示效果
外观Style自定义见这篇文章:WPF自定义按钮外形
Simple WPF: WPF 实现按钮的长按,短按功能

参考链接

UIElement.MouseLeftButtonDown Event
用户控件自定义 DependencyProperty 属性使用教程
WPF 中 DispatcherTimer 计时器
如何:创建自定义路由事件
WPF 自定义带自定义参数路由事件
Use WPF Style in another assemble