翼度科技»论坛 编程开发 .net 查看内容

WPF --- 触摸屏下的两个问题

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
引言

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

具体场景就是一个配置界面, ScrollViewer 中包含一个StackPanel 然后纵向堆叠,已滚动的方式查看,然后包含多个 TextBlock 、 TextBox 以及DataGrid ,期间遇到了两个问题:

  • WPF在触摸屏下,如果有滚动条(ScrollViewer)的情况下,默认包含触底反馈的功能,就是触摸屏滑动到底或从底滑到顶,界面都会出现抖动的情况。
  • 触摸屏下,当触点处于 DataGrid 中时,无法滚动界面。
大概像这样:

解决方案

触底反馈抖动的问题

先来看第一个问题,这个其实是由于 ManipulationBoundaryFeedback 这个事件引起的:

最简单的做法,就是在对应包含ScrollViewer 的 UI 元素绑定它的反馈事件,然后在注册方法中设置 e.Handled = true; ,这样中断了事件继续冒泡或隧道传播,比如这样
  1. // 在Xaml中,在对应的 UIElement 上绑定ManipulationBoundaryFeedback="UIElement_ManipulationBoundaryFeedback"
  2. //Code-Behind中 ,
  3. private void UIElement_ManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e)
  4. {
  5.     e.Handled = true;
  6. }
复制代码
但是这样就需要你在每一个界面都添加该事件,代码冗余,那么就可以使用附加属性的方式,写一个 ManipulationBoundaryFeedbackAttachedProperties,各个界面直接使用,像这样实现:
  1. public class ManipulationBoundaryFeedbackAttachedProperties
  2. {
  3.     public static bool GetIsFeedback(DependencyObject obj)
  4.     {
  5.         return (bool)obj.GetValue(IsFeedbackProperty);
  6.     }
  7.     public static void SetIsFeedback(DependencyObject obj, bool value)
  8.     {
  9.         obj.SetValue(IsFeedbackProperty, value);
  10.     }
  11.     public static readonly DependencyProperty IsFeedbackProperty =
  12.         DependencyProperty.RegisterAttached("IsFeedback", typeof(bool), typeof(UIElement), new PropertyMetadata(true,
  13.             (s, e) =>
  14.             {
  15.                 var target = s as UIElement;
  16.                 if (target != null)
  17.                     target.ManipulationBoundaryFeedback += Target_ManipulationBoundaryFeedback;
  18.             }));
  19.     private static void Target_ManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e)
  20.     {
  21.         var target = sender as UIElement;
  22.         if (target != null)
  23.         {
  24.             if (!GetIsFeedback(target))
  25.             {
  26.                 e.Handled = true;
  27.             }
  28.         }
  29.     }
  30. }
复制代码
像这样使用:
  1. <ScrollViewer local:ManipulationBoundaryFeedbackAttachedProperties.IsFeedback="true">
  2.      ...
  3. </ScrollViewer>   
复制代码
这样就完美解决了!
触点在DataGrid中无法滚动的问题

这个问题,其实不光在 DataGrid中有,触点在 TextBox 、ListView、ListBox,这一类内置有 ScrollViewer 的控件内,都有同样的问题,而且不光是触摸屏无法滚动,鼠标滑轮也无法滚动。我处理这个问题的时候,是先处理的鼠标滑轮无法滚动,处理方案就是根据鼠标的偏移量,手动设置 ScrollViewer 的位置,如下:
  1. private void DataGrid_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
  2. {
  3.     var dataGrid = (DataGrid)sender;
  4.     // 获取
  5.     var scrollViewer = GetScrollViewer(dataGrid);
  6.     if (scrollViewer != null)
  7.     {
  8.         if (scrollViewer.ViewportHeight + scrollViewer.VerticalOffset >= scrollViewer.ExtentHeight && e.Delta <= 0)
  9.         {
  10.             scrollViewer.LineDown();
  11.         }
  12.         else if (scrollViewer.VerticalOffset == 0 && e.Delta >= 0)
  13.         {
  14.             scrollViewer.LineUp();
  15.         }
  16.     }
  17. }
  18. public ScrollViewer GetScrollViewer(UIElement element)
  19. {
  20.     if (element == null) return null;
  21.     ScrollViewer retour = null;
  22.     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element) && retour == null; i++)
  23.     {
  24.         if (VisualTreeHelper.GetChild(element, i) is ScrollViewer)
  25.         {
  26.             retour = (ScrollViewer)(VisualTreeHelper.GetChild(element, i));
  27.         }
  28.         else
  29.         {
  30.             retour = GetScrollViewer(VisualTreeHelper.GetChild(element, i) as UIElement);
  31.         }
  32.     }
  33.     return retour;
  34. }
复制代码
这样就解决了,当鼠标位于 DataGrid 中时,使用滑轮界面无法滚动的问题,那么解决触摸屏触点在 DataGrid 中无法滚动的问题,也是一样的思路,根据触点的偏移量,模拟鼠标滚轮的偏移量,在调用鼠标滚动事件,模拟滚动,代码如下:
  1. private const double TouchMoveThreshold = 20; // 触摸滚动的阈值
  2. private Point lastTouchPosition; // 上一次触摸的位置
  3. private void DataGrid_PreviewTouchMove(object sender, System.Windows.Input.TouchEventArgs e)
  4. {
  5.     // 获取当前触摸位置
  6.     Point currentTouchPosition = e.GetTouchPoint((IInputElement)sender).Position;
  7.     // 计算触摸移动的差值
  8.     double deltaY = currentTouchPosition.Y - lastTouchPosition.Y;
  9.     // 如果触摸移动超过阈值,则模拟鼠标滚动
  10.     if (Math.Abs(deltaY) > TouchMoveThreshold)
  11.     {
  12.         // 设置鼠标滚动的差值
  13.         int mouseWheelDelta = (int)(deltaY / TouchMoveThreshold) * SystemParameters.WheelScrollLines;
  14.         // 创建模拟的鼠标滚动事件参数
  15.         var mouseWheelEventArgs = new MouseWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, mouseWheelDelta);
  16.         mouseWheelEventArgs.RoutedEvent = UIElement.MouseWheelEvent;
  17.         DataGrid_MouseWheel(sender, mouseWheelEventArgs);
  18.         // 更新上一次触摸位置
  19.         lastTouchPosition = currentTouchPosition;
  20.     }
  21. }
复制代码
这样,触摸屏下,触点在 DataGrid 中无法滚动的问题,就解决了。
小结

总的来说,大部分鼠标和触摸屏事件是类似的,但是有些场景下,可能两者不通用的。所以可能需要自行测试一下,保证软件的稳定性。
本文中的解决方案不一定最完美的解决方案,如果各位看官有更好的解决方案,望不吝赐教。

来源:https://www.cnblogs.com/pandefu/p/18060368
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具