WPF --- 触摸屏下的两个问题
引言
本片文章分享一下之前遇到的WPF应用在触摸屏下使用时的两个问题。
场景
具体场景就是一个配置界面, ScrollViewer 中包含一个StackPanel 然后纵向堆叠,已滚动的方式查看,然后包含多个 TextBlock 、 TextBox 以及DataGrid ,期间遇到了两个问题:
- WPF在触摸屏下,如果有滚动条(
ScrollViewer)的情况下,默认包含触底反馈的功能,就是触摸屏滑动到底或从底滑到顶,界面都会出现抖动的情况。 - 触摸屏下,当触点处于
DataGrid中时,无法滚动界面。
大概像这样:

解决方案
触底反馈抖动的问题
先来看第一个问题,这个其实是由于 ManipulationBoundaryFeedback 这个事件引起的:

最简单的做法,就是在对应包含ScrollViewer 的 UI 元素绑定它的反馈事件,然后在注册方法中设置 e.Handled = true; ,这样中断了事件继续冒泡或隧道传播,比如这样
// 在Xaml中,在对应的 UIElement 上绑定ManipulationBoundaryFeedback="UIElement_ManipulationBoundaryFeedback"
//Code-Behind中 ,
private void UIElement_ManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e)
{
e.Handled = true;
}
但是这样就需要你在每一个界面都添加该事件,代码冗余,那么就可以使用附加属性的方式,写一个 ManipulationBoundaryFeedbackAttachedProperties,各个界面直接使用,像这样实现:
public class ManipulationBoundaryFeedbackAttachedProperties
{
public static bool GetIsFeedback(DependencyObject obj)
{
return (bool)obj.GetValue(IsFeedbackProperty);
}
public static void SetIsFeedback(DependencyObject obj, bool value)
{
obj.SetValue(IsFeedbackProperty, value);
}
public static readonly DependencyProperty IsFeedbackProperty =
DependencyProperty.RegisterAttached("IsFeedback", typeof(bool), typeof(UIElement), new PropertyMetadata(true,
(s, e) =>
{
var target = s as UIElement;
if (target != null)
target.ManipulationBoundaryFeedback += Target_ManipulationBoundaryFeedback;
}));
private static void Target_ManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e)
{
var target = sender as UIElement;
if (target != null)
{
if (!GetIsFeedback(target))
{
e.Handled = true;
}
}
}
}
像这样使用:
<ScrollViewer local:ManipulationBoundaryFeedbackAttachedProperties.IsFeedback="true">
...
</ScrollViewer>
这样就完美解决了!
触点在DataGrid中无法滚动的问题
这个问题,其实不光在 DataGrid中有,触点在 TextBox 、ListView、ListBox,这一类内置有 ScrollViewer 的控件内,都有同样的问题,而且不光是触摸屏无法滚动,鼠标滑轮也无法滚动。我处理这个问题的时候,是先处理的鼠标滑轮无法滚动,处理方案就是根据鼠标的偏移量,手动设置 ScrollViewer 的位置,如下:
private void DataGrid_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
var dataGrid = (DataGrid)sender;
// 获取
var scrollViewer = GetScrollViewer(dataGrid);
if (scrollViewer != null)
{
if (scrollViewer.ViewportHeight + scrollViewer.VerticalOffset >= scrollViewer.ExtentHeight && e.Delta <= 0)
{
scrollViewer.LineDown();
}
else if (scrollViewer.VerticalOffset == 0 && e.Delta >= 0)
{
scrollViewer.LineUp();
}
}
}
public ScrollViewer GetScrollViewer(UIElement element)
{
if (element == null) return null;
ScrollViewer retour = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element) && retour == null; i++)
{
if (VisualTreeHelper.GetChild(element, i) is ScrollViewer)
{
retour = (ScrollViewer)(VisualTreeHelper.GetChild(element, i));
}
else
{
retour = GetScrollViewer(VisualTreeHelper.GetChild(element, i) as UIElement);
}
}
return retour;
}
这样就解决了,当鼠标位于 DataGrid 中时,使用滑轮界面无法滚动的问题,那么解决触摸屏触点在 DataGrid 中无法滚动的问题,也是一样的思路,根据触点的偏移量,模拟鼠标滚轮的偏移量,在调用鼠标滚动事件,模拟滚动,代码如下:
private const double TouchMoveThreshold = 20; // 触摸滚动的阈值
private Point lastTouchPosition; // 上一次触摸的位置
private void DataGrid_PreviewTouchMove(object sender, System.Windows.Input.TouchEventArgs e)
{
// 获取当前触摸位置
Point currentTouchPosition = e.GetTouchPoint((IInputElement)sender).Position;
// 计算触摸移动的差值
double deltaY = currentTouchPosition.Y - lastTouchPosition.Y;
// 如果触摸移动超过阈值,则模拟鼠标滚动
if (Math.Abs(deltaY) > TouchMoveThreshold)
{
// 设置鼠标滚动的差值
int mouseWheelDelta = (int)(deltaY / TouchMoveThreshold) * SystemParameters.WheelScrollLines;
// 创建模拟的鼠标滚动事件参数
var mouseWheelEventArgs = new MouseWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, mouseWheelDelta);
mouseWheelEventArgs.RoutedEvent = UIElement.MouseWheelEvent;
DataGrid_MouseWheel(sender, mouseWheelEventArgs);
// 更新上一次触摸位置
lastTouchPosition = currentTouchPosition;
}
}
这样,触摸屏下,触点在 DataGrid 中无法滚动的问题,就解决了。
小结
总的来说,大部分鼠标和触摸屏事件是类似的,但是有些场景下,可能两者不通用的。所以可能需要自行测试一下,保证软件的稳定性。
本文中的解决方案不一定最完美的解决方案,如果各位看官有更好的解决方案,望不吝赐教。
WPF --- 触摸屏下的两个问题的更多相关文章
- 水晶报表在vs2010 WPF环境下的尝试
原文:水晶报表在vs2010 WPF环境下的尝试 由于VS2010没有集成水晶报表组件,尝试前必须先安装 水晶报表 for VS2010,若机器未安装的可点击这里>>>下载安装 新建 ...
- WPF多线程UI更新——两种方法
WPF多线程UI更新——两种方法 前言 在WPF中,在使用多线程在后台进行计算限制的异步操作的时候,如果在后台线程中对UI进行了修改,则会出现一个错误:(调用线程无法访问此对象,因为另一个线程拥有该对 ...
- 在tomcat下部署两个或多个项目时 log4j和web.xml配置webAppRootKey 的问题(转)
在tomcat下部署两个或多个项目时 web.xml文件中最好定义webAppRootKey参数,如果不定义,将会缺省为"webapp.root",如下: <!-- 应用路径 ...
- Centos7下部署两套python版本并存
Centos7下部署两套python版本并存 需求说明:centos7.2系统的开发机器上已经自带了python2.7版本,但是开发的项目中用的是python3.5版本,为了保证Centos系统的 ...
- Linux 下启动两个tomcat
Linux 下启动两个tomcat 闲来无事学习nginx,想要配置个load balance.可是先决条件是:得有两个web容器.两个电脑是不用想了.只能想办法在一个机器上启动两个tomcat.原以 ...
- Linux下配置两个或多个Tomcat启动
Linux下配置两个或多个Tomcat启动 (2012-08-14 11:59:31) 转载▼ 标签: 杂谈 分类: linux_tomcat 步骤如下: (1)修改/etc/profile文件.添加 ...
- WPF dataGrid下的ComboBox的绑定
WPF dataGrid下的ComboBox的绑定 Wpf中dataGrid中的某列是comboBox解决这个问题费了不少时间,不废话了直接上代码 xaml 代码 <DataGridTempla ...
- windows下的两个等待函数
windows下的两个等待技术 第一种: Win32 Sleep()函数 这个函数要求操作系统中止线程动作.直到读过某个指定的时间之后才恢复.能在某个线程结束时(而不是某段时间结束时)被调 ...
- wpf 触摸屏 button 背景为null的 问题
原文:wpf 触摸屏 button 背景为null的 问题 <!-- button样式--> <Style x:Key="myBtn" TargetType=&q ...
- NAT 模式下有两个虚拟机 网段不一样,一台可上网,可ping通,一台上不了网且ping不通
NAT 模式下有两个虚拟机 网段不一样,一台可上网,可ping通,一台上不了网且ping不通直接修改网段的话,会登录不上去,解决方法:设置>网络适配器>高级>生成mac地址重新登陆即 ...
随机推荐
- IM开源项目OpenIM部署文档-从准备工作到nginx配置
IM开源项目OpenIM部署文档-从准备工作到nginx配置 2022-11-14 22:27·OpenIM 一.准备工作 运行环境 linux系统即可, Ubuntu 7.5.0-3ubuntu1~ ...
- 使用emmylua调试slua
使用emmylua调试slua的方法 在lua的入口中加上emmylua的debug代码 在slua的LuaState.loaderDelegate委托中,添加判断如果是load_file_name= ...
- 从零开始配置 vim(9)——初始配置
虽然本系列文章叫做从0开始配置vim,似乎我们从一开始就要写vimrc配置文件,但是我们并没有这么做.我们先经过几篇文章了解了下面的几个内容 如何设置vim属性,从而改变vim的特征 配置快捷键,以提 ...
- 《Spring 手撸专栏》| 开篇介绍,我要带新人撸 Spring 啦!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 不正经!写写面经,去撸Spring源码啦? 是的,在写了4篇关于Spring核心源码 ...
- Mybatis 源码系列:领略设计模式在 Mybatis 其中的应用
目录 一.Builder模式 二.工厂模式 三.单例模式 四.代理模式 五.组合模式 六.模板方式模式 七.适配器模式 八.装饰器模式 九.迭代器模式 虽然我们都知道有23种设计模式,但是大多停留在概 ...
- ch57x/ch58x开启仿真
本次使用的平台是MounRiver Studio,使用的是WCH的CH582m与WCH-LinkE 仿真之前确保LinkE处在Risc-V模式下 空闲时蓝灯常灭 Step1:首先通过ISP工具开启两 ...
- ASP.NET Core分布式项目实战(oauth2 + oidc 实现 server部分)--学习笔记
任务15:oauth2 + oidc 实现 server部分 基于之前快速入门的项目(MvcCookieAuthSample): https://www.cnblogs.com/MingsonZhen ...
- Hive的基本概念
一.Hive基本概念 1.什么是Hive? hive是基于Hadoop的一个数据仓库工具,用来进行数据提取.转化.加载.可以存储.查询和分析存储在Hadoop中的大规模数据. hive数据仓库工具能将 ...
- .NET应用程序7种最常见的性能问题及其解决方案
译者注:这篇文章依然是介绍.NET Framework框架下的性能问题排查,可能并不直接适用于.NET Core,但有时也能提供一些参考. .NET应用程序7种最常见的性能问题及其解决方案 原文地 ...
- 计网学习笔记四 Bridge && Switch
在前面的学习中,我们学习了MAC和LAN.在一个LAN里可以通信是很不错的,我们可以用一些东西让它变得更加不错!那就是我们接下来学习的网桥和交换机,其中包括了一点802.1D机制. Bridge 网桥 ...