项目需求:
1、项目场景:用户长按按钮两秒后触发按钮事件,主要目的是防止用户误操作。为了提高用户操作体验,所以在用户长按该按钮时,添加了一个动画,效果如下:
2、思路代码:在Button的MouseDown
事件中启动动画(动画特效时间可设置),在动画结束后执行按钮功能函数。在MouseUp
事件中判断动画是否执行结束,若未执行结束,则及时关闭动画。
问题描述
在实在该需求时,发现了一个很有意思的问题,在开发电脑上面使用鼠标点击测试时,未发现任何问题,在用户长按时长未达到设定时间时,动画可以随时结束。当使用另一台触摸屏电脑测试时,发现当快速点击该按钮时(相当于单击),动画会继续执行,无法触发MouseUp事件。
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
animation.Start();
}
private void Button_MouseUp(object sender, MouseButtonEventArgs e)
{
animation.Stop();
}
解决方案:
方案一(跳过MouseUp事件,动画开始后启动线程监控系统的鼠标状态):
Thread animation;
private void operateOilPump_MouseDown(object sender, MouseButtonEventArgs e)
{
animation = new Thread(StartAnimation);
animation.IsBackground = true;
animation.Start();
}
[DllImport("user32.dll")]
static extern short GetAsyncKeyState(int nVirtKey);
private void StartAnimation()
{
while (true)
{
if (GetAsyncKeyState(0x01) != 0)
{
//动画执行程序
}
else
{
//判断按钮长按时间是否达到,若达到设定时间,则执行按钮功能函数
}
Thread.Sleep(20);
}
}
方案二(解决MouseUp不触发的问题)
经过查阅资料,发现这可能跟路由顺序有关,控件在捕获了MouseLeftButtonDown或MouseLeftButtonUp事件后,会将该事件的"Handled"设置为true,这个属性是用在路由事件中的,当某个控件得到一个RoutedEvent,就会检测Handled是否为true,为true则忽略该事件。并且,控件本身的Click事件,相当于将MouseLeftButtonDown或MouseLeftButtonUp事件抑制掉了,转换成了Click事件。
在初始化的函数里利用UIElement的AddHandler方法,显式的增加这个事件。
方法说明:
UIElement.AddHandler方法 (RoutedEvent, Delegate, Boolean)
为指定的路由事件添加路由事件处理程序,并将该处理程序添加到当前元素的处理程序集合中。将 HandledEventsToo 指定为 true 时,可为已标记为由其他元素在事件路由过程中处理的路由事件调用所提供的处理程序。
在初始化函数中添加以下代码:
this.AddHandler(Button.MouseDownEvent, new MouseButtonEventHandler(Btn_MouseDown), true);
this.AddHandler(Button.MouseUpEvent, new MouseButtonEventHandler(Btn_MouseUp), true);