引言

本片文章分享一下之前遇到的WPF应用在触摸屏下使用时的两个问题。

场景

具体场景就是一个配置界面, ScrollViewer 中包含一个StackPanel 然后纵向堆叠,已滚动的方式查看,然后包含多个 TextBlockTextBox 以及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中有,触点在 TextBoxListViewListBox,这一类内置有 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 --- 触摸屏下的两个问题的更多相关文章

  1. 水晶报表在vs2010 WPF环境下的尝试

    原文:水晶报表在vs2010 WPF环境下的尝试 由于VS2010没有集成水晶报表组件,尝试前必须先安装 水晶报表 for VS2010,若机器未安装的可点击这里>>>下载安装 新建 ...

  2. WPF多线程UI更新——两种方法

    WPF多线程UI更新——两种方法 前言 在WPF中,在使用多线程在后台进行计算限制的异步操作的时候,如果在后台线程中对UI进行了修改,则会出现一个错误:(调用线程无法访问此对象,因为另一个线程拥有该对 ...

  3. 在tomcat下部署两个或多个项目时 log4j和web.xml配置webAppRootKey 的问题(转)

    在tomcat下部署两个或多个项目时 web.xml文件中最好定义webAppRootKey参数,如果不定义,将会缺省为"webapp.root",如下: <!-- 应用路径 ...

  4. Centos7下部署两套python版本并存

    Centos7下部署两套python版本并存   需求说明:centos7.2系统的开发机器上已经自带了python2.7版本,但是开发的项目中用的是python3.5版本,为了保证Centos系统的 ...

  5. Linux 下启动两个tomcat

    Linux 下启动两个tomcat 闲来无事学习nginx,想要配置个load balance.可是先决条件是:得有两个web容器.两个电脑是不用想了.只能想办法在一个机器上启动两个tomcat.原以 ...

  6. Linux下配置两个或多个Tomcat启动

    Linux下配置两个或多个Tomcat启动 (2012-08-14 11:59:31) 转载▼ 标签: 杂谈 分类: linux_tomcat 步骤如下: (1)修改/etc/profile文件.添加 ...

  7. WPF dataGrid下的ComboBox的绑定

    WPF dataGrid下的ComboBox的绑定 Wpf中dataGrid中的某列是comboBox解决这个问题费了不少时间,不废话了直接上代码 xaml 代码 <DataGridTempla ...

  8. windows下的两个等待函数

    windows下的两个等待技术 第一种: Win32  Sleep()函数      这个函数要求操作系统中止线程动作.直到读过某个指定的时间之后才恢复.能在某个线程结束时(而不是某段时间结束时)被调 ...

  9. wpf 触摸屏 button 背景为null的 问题

    原文:wpf 触摸屏 button 背景为null的 问题 <!-- button样式--> <Style x:Key="myBtn" TargetType=&q ...

  10. NAT 模式下有两个虚拟机 网段不一样,一台可上网,可ping通,一台上不了网且ping不通

    NAT 模式下有两个虚拟机 网段不一样,一台可上网,可ping通,一台上不了网且ping不通直接修改网段的话,会登录不上去,解决方法:设置>网络适配器>高级>生成mac地址重新登陆即 ...

随机推荐

  1. 紫 distance

    仅此纪念我爆掉的T3 紫,即RE,运行出错,梦幻,而又不失杀气 根据<雪distance>改编,分为提交前,评测前,评测时,评测后 你说我考试AK,可我却运行出错 任凭无尽的懊悔将我淹没, ...

  2. 环境调试bug【一】

    1.报错修改`np.bool`---bool H:\Anaconda3-2020.02\envs\parl\lib\site-packages\paddle\fluid\framework.py:54 ...

  3. 1.10 内存ShellCode注入与格式化

    ShellCode 的格式化与注入功能在实战应用中也尤为重要,格式化Shellcode是指将其转换为可执行的二进制格式,使其能够在内存中运行.注入Shellcode是指将格式化的Shellcode注入 ...

  4. Java并发编程面试题

    Synchronized 用过吗,其原理是什么? Synchronized是jvm实现的一种互斥同步访问方式,底层是基于对象的监视器monitor实现的. 被synchronize修饰的代码在反编译后 ...

  5. MySQL8.0清空binlog

    环境 centos7.9 mysql  Ver 8.0.32 登录MySQL,查看binlog日志 #查看binlog日志开启状态,log_bin值为ON表示开启状态 mysql> show v ...

  6. Swift中UITableViewDiffableDataSource的使用

    在 iOS 13 中 Apple 为 UITableView 和 UICollectionView 引入了 DiffableDataSource, 让开发者可以更简单高效的实现 UITableView ...

  7. 关于Windows11的优化内容 - 进阶者系列 - 学习者系列文章

    这几天无事,想起上次刚重装的Windows 11操作系统,对于系统优化的内容想记录一下,以前没写过相关的博文,这次就做个记录吧.对于Windows 11,已经出来几年了,相关的设置啥的也有,就是优化方 ...

  8. 【内存操作】C语言内存函数介绍以及部分模拟实现【初学者保姆级福利】超详细的解释和注释

    C语言 内存函数的使用以及部分模拟实现 求个赞求个赞求个赞求个赞 谢谢 先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记关注 ...

  9. KVM环境:Active console session exists for this domain

    做测试过程中被迫换电脑,但没有关掉原电脑的连接,所以用其他电脑连接测试环境时,发现之前的kvm测试环境因没有断开,无法连接: error: operation failed: Active conso ...

  10. IDEA中使用ChatGPT

    IDEA中使用ChatGPT 在IDEA中安装ChatGPT插件,可以帮助写基础逻辑代码,提高工作效率和学习效率,有兴趣可以玩一下. 插件名为 Bito. 1. 什么是Bito Bito是一款在Int ...