双击时,防止单击WPF控件

Sam*_*Sam 5 c# wpf click double-click

Image控制了PreviewMouseLeftButtonDown事件处理.逻辑是在单击发生时更改图像内容,并在双击时激活其他视觉样式.

我知道ClickCount属性就像一些答案所说的那样(例如这个)并且成功地区分单击/双击,但问题是单击总是发生,其中双击跟随或不跟随下一刻(这是公平的,无论如何).因此,双击处理两个操作 - 单击,下一次双击.

问题:有没有防止单一的点击方法之前是双击后存在的权利,比其他处理这种情况有某种神奇的计时器?

编辑:
我发现了一个好的评论问题,这与Windows资源管理器进行了类比 - 单击所选文件后如何等待,并开始重命名,确保第一次点击后没有其他点击.
延迟肯定会存在以解决这个问题的目的,但它是否意味着Windows资源管理器使用完全计时器,或者它可能有一些其他选项(某些属性或事件可以等待)以保持单击以防双击发生?

Sam*_*Sam 7

最后没有收到与定时器无关的解决方案的建议(我也没有发现任何一个),所以这里是一个简单的例子,当双击发生时如何防止单击.

XAML:

<Window x:Class="StackOverflow.DoubleClickExample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="100" Width="150"
    MouseDown="RootElement_OnMouseDown">
</Window>
Run Code Online (Sandbox Code Playgroud)

代码隐藏:

namespace StackOverflow.DoubleClickExample
{
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;

    public partial class MainWindow : Window
    {
        [DllImport("user32.dll")]
        public static extern uint GetDoubleClickTime();

        public MainWindow()
        {
            this.InitializeComponent();
        }

        private Guid lastGuid = Guid.Empty;

        private void RootElement_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 1)
            {
                // Create new unique id and save it into field.
                var guid = Guid.NewGuid();
                this.lastGuid = guid;

                // Run task asynchronously for ensuring that there is no another click
                // happened in time interval when double-click can occure.
                Task.Run(async () =>
                {
                    // Wait system double-click time interval.
                    await Task.Delay((int)GetDoubleClickTime());

                    // If no double-click occured in awaited time interval, then
                    // last saved id (saved when first click occured) will be unchanged.
                    if (guid == this.lastGuid)
                    {
                        // Here is any logic for single-click handling.
                        Trace.WriteLine("Single-click occured");
                    }
                });

                return;
            }

            // Can be here only when e.ClickCount > 1, so must change last saved unique id.
            // After that, asynchronously running task (for single-click) will detect
            // that id was changed and so will NOT run single-click logic.
            this.lastGuid = Guid.NewGuid();

            // Here is any logic for double-click handling.
            Trace.WriteLine("Double-click occured");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要进行测试,请在窗口区域中单击并跟踪在visual studio中写入输出窗口的消息(菜单视图 - >输出).

另一种方法是在双击时使用CancellationTokenSource并触发其Cancel方法.只需替换lastGuid字段和RootElement_OnMouseDown方法:

private CancellationTokenSource cancellationTokenSource;

private void RootElement_OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ClickCount == 1)
        {
            try
            {
                this.cancellationTokenSource = new CancellationTokenSource();
                var token = this.cancellationTokenSource.Token;

                // Run task asynchronously for ensuring that there is no another click
                // happened in time interval when double-click can occure.
                Task.Run(async () =>
                {
                    // Wait system double-click time interval.
                    await Task.Delay((int)GetDoubleClickTime(), token);

                    // Here is any logic for single-click handling.
                    Trace.WriteLine("Single-click occured");
                }, token);
            }
            catch (OperationCanceledException)
            {
                // This exception always occure when task is cancelled.
                // It happening by design, just ignore it.
            }

            return;
        }

        // Cancel single-click task.
        if (this.cancellationTokenSource != null)
        {
            this.cancellationTokenSource.Cancel();
        }

        // Here is any logic for double-click handling.
        Trace.WriteLine("Double-click occured");
    }
Run Code Online (Sandbox Code Playgroud)