双击时,防止单击WPF控件

时间:2015-08-18 15:56:14

标签: c# wpf click double-click

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

我知道'use strict'; //app global variable //this is the controller that handles post requests //declare services as dependecies $http, $location, custom service apiServiceWeb app.controller('navigationController', function($scope, $route, $rootScope, $http, $location, $cookies, setCredentials) { //get what is in the cookie var cookieValue = setCredentials.getCookie('globals'); if (cookieValue == '[object Object]') { //redirect to home $location.path("/"); //remove cookie //setCredentials.removeCookie('globals'); } //hide menu in certain paths if ($location.path() == '/' || $location.path() == 'signup' || cookieValue == '[object Object]') { //hide menu $scope.isConnected = true; } else { $rootScope.$watch('globals', function() { //if a currentUser does NOT exist, the hide menu. console.log('changed'); // console.log($rootScope.globals); if (cookieValue = null) { $scope.isConnected = true; } else { //show menu, user is logged in $scope.isConnected = false; } }); } }); 属性就像一些答案所说(e.g. this)并成功区分单击/双击,但问题是单击发生总是,其他是双击点击跟随或不跟随下一刻(这是公平的,无论如何)。因此,双击处理两个操作 - 单击,下一次双击。

问题:是否有任何方法可以防止单击之前发生在双击之后,除了以某种计时器魔术处理这种情况?

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

2 个答案:

答案 0 :(得分: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>

代码隐藏:

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");
        }
    }
}

进行测试时,在窗口区域进行点击,并在visual studio中跟踪写入输出窗口的消息(菜单视图 - &gt;输出)。

另一种方法是使用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");
    }

答案 1 :(得分:4)

我猜你需要使用计时器。为了获得对于双击仍然有效的最大时间,您可以使用以下函数(已测试;输出为500毫秒):

[DllImport("user32.dll")]
static extern uint GetDoubleClickTime();

(来源:how to get the double-click-time in WPF

通常,当您想要绑定到一个WPF控件时有多个值时,可以使用ItemsSource之类的东西,并将其绑定到视图模型中的List。但我想这对图像控制不起作用。因此,您应该使用计时器并使用上述函数的值作为计时器。