翼度科技»论坛 编程开发 .net 查看内容

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

8

主题

8

帖子

24

积分

新手上路

Rank: 1

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

为了方便在xaml中使用,我们先配置一个DependencyProperty叫做LongPressTime来作为界定长按的阈值
  1. public class LongPressButtonEx : Button
  2. {
  3.         public static readonly DependencyProperty LongPressTimeProperty
  4.             = DependencyProperty.Register("LongPressTime", typeof(int),
  5.                 typeof(LongPressButtonEx), new PropertyMetadata(500));
  6.         public int LongPressTime
  7.         {
  8.             set => SetValue(LongPressTimeProperty, value);
  9.             get => (int)GetValue(LongPressTimeProperty);
  10.         }
  11. }
复制代码
定义完成后可以在Xaml设计器中使用LongPressTime这个拓展属性
  1. <Window x:
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6.         xmlns:local="clr-namespace:LongPressButton"
  7.         mc:Ignorable="d"
  8.         Title="MainWindow" Height="450" Width="800">
  9.     <Grid>
  10.         <local:LongPressButtonEx Width="96" Height="48" LongPressTime="200">
  11.             Button
  12.         </local:LongPressButtonEx>
  13.     </Grid>
  14. </Window>
复制代码
长按的定时器判定方法

C#中的4种定时器,在WPF中需要使用Dispater Timer
定义一个DispatcherTimer来监控是否按下达到了长按
  1. private DispatcherTimer _pressDispatcherTimer;
  2. private void OnDispatcherTimeOut(object sender, EventArgs e)
  3. {
  4.     _pressDispatcherTimer?.Stop();
  5.     Debug.WriteLine($"Timeout {LongPressTime}");
  6. }
  7. protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
  8. {
  9.     base.OnMouseLeftButtonDown(e);
  10.     Debug.WriteLine("Button: Mouse down.");
  11.     if (_pressDispatcherTimer == null)
  12.     {
  13.         _pressDispatcherTimer = new DispatcherTimer();
  14.         _pressDispatcherTimer.Tick += OnDispatcherTimeOut;
  15.         _pressDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, LongPressTime);
  16.         _pressDispatcherTimer.Start();
  17.         Debug.WriteLine("Button: Timer started");
  18.     }
  19. }
  20. protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  21. {
  22.     base.OnMouseLeftButtonUp(e);
  23.     Debug.WriteLine("Button: Mouse up.");
  24.     _pressDispatcherTimer?.Stop();
  25.     _pressDispatcherTimer = null;
  26. }
复制代码
现在分别点击和长按按钮可以看到调试输出
  1. ...
  2. # 点击
  3. Button: Mouse down.
  4. Button: Timer started
  5. Button: Mouse up.
  6. # 长按
  7. Button: Mouse down.
  8. Button: Timer started
  9. Timeout 200
  10. Button: Mouse up.
复制代码
实现长按事件的定义

现在作为一个自定义控件,我们需要在长按后发出一个RoutedEvent,并修改部分之前的代码抛出事件
  1. /// <summary>
  2. /// LongPress Routed Event
  3. /// </summary>
  4. public static readonly RoutedEvent LongPressEvent
  5.     = EventManager.RegisterRoutedEvent("LongPress",
  6.         RoutingStrategy.Bubble,
  7.         typeof(RoutedEventHandler),
  8.         typeof(LongPressButtonEx));
  9. public event RoutedEventHandler LongPress
  10. {
  11.     add => AddHandler(LongPressEvent, value);
  12.     remove => RemoveHandler(LongPressEvent, value);
  13. }
  14. private void OnDispatcherTimeOut(object sender, EventArgs e)
  15. {
  16.     _pressDispatcherTimer?.Stop();
  17.     Debug.WriteLine($"Timeout {LongPressTime}");
  18.     RaiseEvent(new RoutedEventArgs(LongPressEvent));    // raise the long press event
  19. }
复制代码
回到窗体的代码中,添加事件的响应
  1. <local:LongPressButtonEx Height="48" Width="256" LongPressTime="200"
  2.         LongPress="LongPressButtonEx_LongPress"
  3.         Click="LongPressButtonEx_Click">
  4.     Click or Long Press Me!
  5. </local:LongPressButtonEx>
复制代码
C#代码如下,长按按钮会显示Long Pressed,单击会是Click
  1. private void LongPressButtonEx_LongPress(object sender, RoutedEventArgs e)
  2. {
  3.     if (sender is LongPressButtonEx btn)
  4.     {
  5.         btn.Content = "Long Pressed";
  6.     }
  7. }
  8. private void LongPressButtonEx_Click(object sender, RoutedEventArgs e)
  9. {
  10.     if (sender is LongPressButtonEx btn)
  11.     {
  12.         btn.Content = "Clicked";
  13.     }
  14. }
复制代码

发现Click和LongPress都可以响应,但是当松开按钮时又变成了Click,原因是鼠标松开时响应了默认的Click事件
现在对按钮控件默认的OnClick函数稍作修改,可以让Click也不出问题
  1. /// <summary>
  2. /// DependencyProperty for IsLongPress
  3. /// </summary>
  4. public static readonly DependencyProperty IsLongPressProperty
  5.     = DependencyProperty.Register("IsLongPress", typeof(bool),
  6.         typeof(LongPressButtonEx), new PropertyMetadata(false));
  7. public bool IsLongPress
  8. {
  9.     set => SetValue(IsLongPressProperty, value);
  10.     get => (bool)GetValue(IsLongPressProperty);
  11. }
  12. private void OnDispatcherTimeOut(object sender, EventArgs e)
  13. {
  14.     IsLongPress = true;
  15.     _pressDispatcherTimer?.Stop();
  16.     Debug.WriteLine($"Timeout {LongPressTime}");
  17.     RaiseEvent(new RoutedEventArgs(LongPressEvent));    // raise the long press event
  18. }
  19. protected override void OnClick()
  20. {
  21.     if (!IsLongPress)
  22.     {
  23.         base.OnClick();
  24.     }
  25.     else
  26.     {
  27.         RaiseEvent(new RoutedEventArgs(LongPressReleaseEvent));    // raise the long press event
  28.         IsLongPress = false;
  29.     }
  30. }
复制代码
之后再进行点击操作,我们就可以看到符合预期的结果

长按+Style按钮的展示效果
外观Style自定义见这篇文章:WPF自定义按钮外形

参考链接

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

来源:https://www.cnblogs.com/mrchip/p/18289007
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具