Skip to content

WPF 单击与双击操作区分

Published: at 20:00

背景

如果不需要严格区分单击与双击操作,可以直接通过 MouseButtonEventArgs 中的 ClickCount 属性来进行判断。

private void MyMouseDownHandler(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
// Handle double-click
}
}

但上述写法有个问题是,如果我需要在单击和双击时执行不同的操作,则无法满足需求。 因为用户双击时,会首先触发一次 e.ClickCount == 1 的单击。

mouseevent - Distinguish between mouse doubleclick and mouse click in wpf - Stack Overflow

实现

using System;
using System.Windows.Input;
using System.Windows.Threading;
namespace xxx.xxx;
/// <summary>
/// 通过延迟判断来区分鼠标单击和双击操作,
/// 对于需要严格区分单击和双击的场景使用。
/// 影响:单击的响应会有延迟,延迟 220 ms
/// </summary>
internal class MouseDoubleClickHelper
{
private static readonly TimeSpan DoubleClickCheckTime = TimeSpan.FromMilliseconds(220); // ms
private DateTime _lastClickTime = DateTime.MinValue;
private readonly DispatcherTimer _timer;
/// <summary>
/// 单击时的动作
/// </summary>
public Action<object, MouseButtonEventArgs>? ClickAction { get; set; }
/// <summary>
/// 双击时的动作
/// </summary>
public Action<object, MouseButtonEventArgs>? DoubleClickAction { get; set; }
public MouseDoubleClickHelper(Dispatcher dispatcher)
{
_timer = new DispatcherTimer(DoubleClickCheckTime, DispatcherPriority.Input, TimerCallback, dispatcher);
}
private void TimerCallback(object? _, EventArgs __)
{
// ReSharper disable once UsePatternMatching
var args = _timer.Tag as (object sender, MouseButtonEventArgs e)?;
if (args != null)
{
// 计时器到,没有出现第二次点击,则认为是单击动作,执行单击操作
ClickAction?.Invoke(args.Value.sender, args.Value.e);
_timer.Tag = null;
}
}
/// <summary>
/// 鼠标点击时调用
/// </summary>
public void OnMouseDown(object sender, MouseButtonEventArgs e)
{
var now = DateTime.Now;
var span = now - _lastClickTime;
if (span > DoubleClickCheckTime)
{
// 首次点击,不立即执行,启动计时器,延迟执行
_timer.Tag = (sender, e);
_timer.Start();
}
else if (span <= DoubleClickCheckTime)
{
// 停掉单击的执行
_timer.Tag = null;
_timer.Stop();
if (e.ClickCount == 2)
{
// 执行双击动作
DoubleClickAction?.Invoke(sender, e);
}
}
_lastClickTime = now;
}
}

通过延迟判断,来过滤掉双击时,第一次鼠标点击的触发。

带来的问题是,正常的单击操作,会被延迟触发。

如果你期望使用更精确的 DoubleClickCheckTime,可以使用 System.Windows.Forms.SystemInformation.DoubleClickTime

SystemInformation.DoubleClickTime 属性 (System.Windows.Forms) | Microsoft Learn

在 WPF 中,需要先添加 WindowForms 的引用。

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
</Project>

其它

在 WinForm 下区分单击和双击: 如何区分单击和双击 - Windows Forms .NET | Microsoft Learn


原文链接: https://blog.jgrass.cc/posts/wpf-double-click-helper/

本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。