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