使用WPF / C#触摸输入:如何定义阈值以区分平移点击

时间:2016-04-28 12:42:44

标签: c# wpf touch multi-touch panning

我目前正在开发使用WPF和(多点触控)电容式触摸屏监视器的应用程序,该监视器被Windows识别为本机触摸设备,即它不需要任何额外的驱动程序。

当我使用WPF按钮并使用触摸点击它时,我收到了一个点击的事件。我的问题是我的一些用户没有执行干净的点击,但是当他们触摸时移动触摸光标的某些像素,所以我的应用程序不再识别点击事件。

有没有办法定义Windows不会将其解释为平移手势的移动阈值,而是将其识别为点击?

1 个答案:

答案 0 :(得分:1)

我想出了这个实现-32像素用于定义阈值。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Willbe.Extensions;

namespace Kiolyn.Wpf
{
  public static class TouchAssist
  {
    public static bool GetTouchAsClick(DependencyObject obj)
      => (bool)obj.GetValue(TouchAsClickProperty);

    public static void SetTouchAsClick(DependencyObject obj, bool value)
      => obj.SetValue(TouchAsClickProperty, value);

    // Using a DependencyProperty as the backing store for SelectOnMouseOver.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TouchAsClickProperty =
        DependencyProperty.RegisterAttached(
          "TouchAsClick",
          typeof(bool),
          typeof(TouchAssist),
          new UIPropertyMetadata(false, OnTouchAsClickChanged));

    // Using a DependencyProperty as the backing store for SelectOnMouseOver.  This enables animation, styling, binding, etc...
    private static readonly DependencyProperty LastExecuteTimeProperty =
        DependencyProperty.RegisterAttached(
          "LastExecuteTime",
          typeof(DateTime),
          typeof(TouchAssist),
          new UIPropertyMetadata(null));

    private static readonly DependencyProperty TouchDownPositionProperty =
        DependencyProperty.RegisterAttached(
          "TouchDownPosition",
          typeof(Point),
          typeof(TouchAssist),
          new UIPropertyMetadata(null));

    static void OnTouchAsClickChanged(DependencyObject d, DependencyPropertyChangedEventArgs ev)
    {
      if (d is Button button)
      {
        button.IsManipulationEnabled = true;

        button.TouchDown += (s, e) =>
        {
          button.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, e.Timestamp, MouseButton.Left)
          {
            RoutedEvent = Mouse.PreviewMouseDownEvent
          });
          button.ClearValue(LastExecuteTimeProperty);
          button.SetValue(TouchDownPositionProperty, e.GetTouchPoint(Application.Current.MainWindow).Position);
        };
        button.TouchUp += (s, e) =>
        {
          var command = button.Command;
          var parameter = button.CommandParameter;
          if (command != null && command.CanExecute(parameter) && button.GetValue(TouchDownPositionProperty) is Point touchDownPosition)
          {
            var touchUpPosition = e.GetTouchPoint(Application.Current.MainWindow).Position;
            var dx = Math.Abs(touchUpPosition.X - touchDownPosition.X);
            var dy = Math.Abs(touchUpPosition.Y - touchDownPosition.Y);
            if (dx < 32 && dy < 32)
            {
              // Should be treated as click
              // Mark the last execute time
              button.SetValue(LastExecuteTimeProperty, DateTime.Now);
              command.Execute(parameter);
            }
          }
        };
        button.PreviewMouseLeftButtonUp += (s, e) =>
        {
          if (button.GetValue(LastExecuteTimeProperty) is DateTime lastExecuteTime && DateTime.Now.Subtract(lastExecuteTime).Milliseconds < 300)
          {
            e.Handled = true;
            button.ReleaseMouseCapture();
          }
          button.ClearValue(LastExecuteTimeProperty);
        };
      }
    }
  }
}

用法:

<Button wpf:TouchAssist.TouchAsClick="True"/>