Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 解决WPF触摸屏灵敏度问题的方法_C#_Wpf_Multi Touch - Fatal编程技术网

C# 解决WPF触摸屏灵敏度问题的方法

C# 解决WPF触摸屏灵敏度问题的方法,c#,wpf,multi-touch,C#,Wpf,Multi Touch,我试图解决电容式触摸屏的灵敏度问题,如果用户的手指太靠近屏幕表面,就会触发WPF按钮 这个问题是,许多用户的手指或手的一部分(除主触指外)靠近屏幕表面,这会导致触发错误的按钮 调整屏幕的灵敏度似乎对我来说没有什么影响,我想我可以尝试修改按钮按下事件,只有在按钮按下超过一定时间后才会触发点击 有人能解释一下我如何创建一个自定义按钮,在触发点击事件之前,该按钮的“按下”时间可以调整 如果可能的话,您可能会很乐意包含一个非常简单的C/WPF应用程序和这样一个自定义按钮 编辑 好的,根据@kidshaw

我试图解决电容式触摸屏的灵敏度问题,如果用户的手指太靠近屏幕表面,就会触发WPF按钮

这个问题是,许多用户的手指或手的一部分(除主触指外)靠近屏幕表面,这会导致触发错误的按钮

调整屏幕的灵敏度似乎对我来说没有什么影响,我想我可以尝试修改按钮按下事件,只有在按钮按下超过一定时间后才会触发点击

有人能解释一下我如何创建一个自定义按钮,在触发点击事件之前,该按钮的“按下”时间可以调整

如果可能的话,您可能会很乐意包含一个非常简单的C/WPF应用程序和这样一个自定义按钮

编辑

好的,根据@kidshaw的回答,我已经使用下面的代码创建了一个子类按钮,但我想我肯定遗漏了一些东西,因为除了默认的Click事件之外,没有调用任何东西

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace AppName
{
    public class TouchButton : Button
    {
        DoubleAnimationUsingKeyFrames _animation;

        public static readonly DependencyProperty DelayElapsedProperty =
         DependencyProperty.Register("DelayElapsed", typeof(double), typeof(TouchButton), new PropertyMetadata(0d));

        public static readonly DependencyProperty DelayMillisecondsProperty =
                DependencyProperty.Register("DelayMilliseconds", typeof(int), typeof(TouchButton), new PropertyMetadata(100));

        public double DelayElapsed
        {
            get { return (double)this.GetValue(DelayElapsedProperty); }
            set { this.SetValue(DelayElapsedProperty, value); }
        }

        public int DelayMilliseconds
        {
            get { return (int)this.GetValue(DelayMillisecondsProperty); }
            set { this.SetValue(DelayMillisecondsProperty, value); }
        }
        private void BeginDelay()
        {
            this._animation = new DoubleAnimationUsingKeyFrames() { FillBehavior = FillBehavior.Stop };
            this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
            this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(this.DelayMilliseconds)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
            this._animation.Completed += (o, e) =>
            {
                this.DelayElapsed = 0d;
                //this.Command.Execute(this.CommandParameter);    // Replace with whatever action you want to perform
                Console.Beep();
                this.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
            };

            this.BeginAnimation(DelayElapsedProperty, this._animation);
        }

        private void CancelDelay()
        {
            // Cancel animation
            this.BeginAnimation(DelayElapsedProperty, null);
        }
        private void TouchButton_TouchDown(object sender, System.Windows.Input.TouchEventArgs e)
        {
            this.BeginDelay();
        }

        private void TouchButton_TouchUp(object sender, System.Windows.Input.TouchEventArgs e)
        {
            this.CancelDelay();
        }

    }
}
TouchButton\u触地方法是如何被调用的?我不是一定要把这个分配给触地得分的球员吗


好的,我添加了一个构造函数并设置了触地/上升事件处理程序,这样可以工作,但CancelDelay不会阻止事件被触发。它似乎工作正常,当用户抬起手指时会被调用,但不会阻止事件被触发。

时间延迟按钮将是最佳选择

我在另一个堆栈溢出答案中提供了一个示例

它使用动画延迟触发命令

希望能有帮助


你几乎可以肯定地想出一个解决办法。我将研究两种方法:

创建一个源于Button的专业化。您可以重写各种处理程序来实现自己的行为。 创建订阅预览鼠标事件的附加依赖项属性。预览事件将允许您截获向上/向下事件,以在标准按钮处理生成单击事件之前注入您自己的行为。 选择1可能是最容易让你动脑的方法。生成单击事件的处理存在于OnMouseLeftButtonDown和OnMouseLeftButtonUp处理程序的ButtonBase中。如果您实现覆盖这两个处理程序的您自己的版本,您应该能够相当容易地引入一个计时器,该计时器仅在用户按下并按住按钮后的某个时间过期时调用OnClick来生成click事件


PS:如果您还没有,我强烈建议您购买一份.NET Reflector。它将允许您轻松查看WPF按钮实现的代码。为了回答这个问题,我很快用它查看了WPF按钮的实现,了解了它是如何工作的。

为了完整起见,这里是我基于@kidshaw的原始答案使用的完整解决方案。也许可以为其他人节省一些时间,把这些碎片拼凑在一起

请注意,我收到了VS Designer错误,抱怨在应用程序名称空间中找不到自定义类。奇怪的是,这似乎并没有发生在早期版本的VS上,所以这可能是VS中的一个bug

TouchButton.cs

在App.xaml中触发IsTouched事件时的自定义动画

XAML使用

<UserControl x:Class="TouchButtonApp.Keyboard1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TouchButtonApp"
             mc:Ignorable="d" 
             d:DesignHeight="352" d:DesignWidth="1024">
    <Grid>
        <Grid Margin="0,0,0,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="90*"/>
                <RowDefinition Height="90*"/>
                <RowDefinition Height="90*"/>
                <RowDefinition Height="90*"/>
            </Grid.RowDefinitions>
            <Grid>
                <Grid.RowDefinitions>

                    <RowDefinition Height="8*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                </Grid.ColumnDefinitions>
                <local:TouchButton x:Name="qButton" Tap="Button_Click" Content="Q"  Grid.Row="1" Style="{DynamicResource characterKeyT}" />
                <local:TouchButton x:Name="wButton" Tap="Button_Click" Content="W"  Grid.Column="1" Grid.Row="1" Style="{DynamicResource characterKeyT}" />
...

你不能用按钮创建一个用户控件,按下按钮启动计时器,100毫秒后手动触发点击事件吗?问题是Windows touch驱动程序似乎无法区分非常轻的触摸和长的触摸。因此,我需要这个按钮来触发事件,如果这个按钮被长时间按下,并且需要一些实验来确定可用性的最佳持续时间。我的猜测是一次按下大约是200-300毫秒,而一次通过的触发器将少于200毫秒。我想我可以在按下时启动计时器,在释放时停止,如果>X触发事件;与其使用ClickEvent,不如创建一个新的ClickEvent并引发它,比如延迟ClickEvent。ClickEvent将在第一次单击时由按钮触发,通过将其分离为自己的事件,您仅在延迟后处理延迟的触发器。感谢我这么做,但我必须添加一个标志IsCancelled,该标志在收到修补事件时设置。因此,当动画完成时,它会检查IsCancelled=true,如果不是,则引发IsTouched事件。然后在引发事件后,我必须将IsTouched属性重置为false,因为它必须是瞬时属性,我使用它来设置颜色褪色的动画。现在在真正的触摸屏上与用户一起测试它!谢谢,看起来它可以通过确保按钮在最短时间内按下来完成这项工作。你能解释一下这段代码的去向吗,或者它都在一个类文件中吗。最好提供一个
购物中心示例应用程序,只有一个屏幕和一个按钮。在一个类文件中创建它。构建你的应用程序,它应该可以从toolboxOK中拖入,但编译器不喜欢this.GetValue或this.SetValue调用或this.\u动画、this.Command等。。这些是否需要一些引用?添加了System.Windows.Controls而不是System.Windows.Forms,它们修复了除“this.\u动画”之外的所有引用。该动画需要声明为类成员变量或字段
<Style x:Key="characterKeyT" TargetType="{x:Type local:TouchButton}">
    <Setter Property="Focusable" Value="False" />
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="Margin" Value="6,4,8,4"/>
    <Setter Property="FontSize" Value="24"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TouchButton}">
                <Grid x:Name="grid">
                    <Border x:Name="border" CornerRadius="0">                                
                        <Border.Background>
                            <SolidColorBrush x:Name="BackgroundBrush" Color="{Binding Source={StaticResource settingsProvider}, Path=Default.ThemeColorPaleGray2}"/>
                        </Border.Background>
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="Black" 
                                          TextElement.FontSize="24"></ContentPresenter>
                    </Border>
                </Grid>
                <ControlTemplate.Resources>
                    <Storyboard x:Key="FadeTimeLine" BeginTime="00:00:00.000" Duration="00:00:02.10">
                        <ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color"                                                 
                                         To="#FF22B0E6" 
                                        Duration="00:00:00.10"/>
                        <ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color"                                                 
                                         To="#FFECE8E8" 
                                        Duration="00:00:02.00"/>
                    </Storyboard>
                </ControlTemplate.Resources>
                <ControlTemplate.Triggers>                            
                    <Trigger Property="IsTouched" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource FadeTimeLine}"/>
                        </Trigger.EnterActions>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource ThemeSolidColorBrushPaleGray}"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="False">
                        <Setter Property="Background" TargetName="border"  Value="{StaticResource ThemeSolidColorBrushPaleGray2}"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Opacity" TargetName="grid" Value="0.25"/>
                    </Trigger>

                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<UserControl x:Class="TouchButtonApp.Keyboard1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TouchButtonApp"
             mc:Ignorable="d" 
             d:DesignHeight="352" d:DesignWidth="1024">
    <Grid>
        <Grid Margin="0,0,0,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="90*"/>
                <RowDefinition Height="90*"/>
                <RowDefinition Height="90*"/>
                <RowDefinition Height="90*"/>
            </Grid.RowDefinitions>
            <Grid>
                <Grid.RowDefinitions>

                    <RowDefinition Height="8*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                    <ColumnDefinition Width="93*"/>
                </Grid.ColumnDefinitions>
                <local:TouchButton x:Name="qButton" Tap="Button_Click" Content="Q"  Grid.Row="1" Style="{DynamicResource characterKeyT}" />
                <local:TouchButton x:Name="wButton" Tap="Button_Click" Content="W"  Grid.Column="1" Grid.Row="1" Style="{DynamicResource characterKeyT}" />
...