【问题标题】:Horizontal scroll on ListViewListView 上的水平滚动
【发布时间】:2014-05-14 21:24:53
【问题描述】:

我目前正在捕获页面上的PointerMoved 事件以与水平菜单一起使用。所以用户可以向左/向右滑动,页面会相应地动画。

这在用户触摸静态元素(TextBlock 等)时有效,但如果他们触摸 ListView,它会捕获触摸事件。

如何实现 ListView,以便当用户垂直滚动时它可以正常工作,但当用户水平滚动时它会将事件传递给我的代码?

【问题讨论】:

    标签: c# xaml listview windows-runtime windows-phone-8.1


    【解决方案1】:

    这是可能的,但你需要一个小技巧。作为参考,我把Rob Caplan's article放在这里。

    让我们开始吧:

    1. 首先 - 您的活动在哪里? - 答案很简单 - 当您启用 ScrollViewer 时,所有事件都会被它拦截并处理。你ListView 只会得到PointerEntered 事件,而在它之后PointerExited,所有进一步的处理都由ScrollViewer 处理。那就是问题所在。但正如我所说,有一种方法可以做你想做的事。

    2. 为此,假设您仅使用 VerticalScroll 定义了 ListView:

      <ListView Name="myList" ScrollViewer.HorizontalScrollMode="Disabled">
      

      当然可以双向进行,但这是一个简单的例子。

    3. 现在让我们看看Page的构造函数:

      PointerPoint firstPoint = null;
      ScrollViewer listScrollviewer = null;
      
      public MainPage()
      {
        this.InitializeComponent();
        myList.ItemsSource = yourItemSource;
        myList.PointerEntered += myList_PointerEntered;
        myList.PointerMoved += myList_PointerMoved;
      }
      

      这里没有什么奇怪的 - 我只是订阅事件,并声明两个变量 firstPoint 和 listScrollviewer,我稍后会用到。

    4. 我们还需要获取我们的ScrollViewer 或ListView - 以下方法可以完成这项工作:

      public static ScrollViewer GetScrollViewer(DependencyObject depObj)
      {
          if (depObj is ScrollViewer) return depObj as ScrollViewer;
      
          for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
          {
              var child = VisualTreeHelper.GetChild(depObj, i);
      
              var result = GetScrollViewer(child);
              if (result != null) return result;
          }
          return null;
      }
      
    5. 现在 - 要启用我们的事件,我们需要禁用 ScrollViewer:

      private ScrollViewer DisableScrolling(DependencyObject depObj)
      {
          ScrollViewer foundOne = GetScrollViewer(depObj);
          if (foundOne != null) foundOne.VerticalScrollMode = ScrollMode.Disabled;
          return foundOne;
      }
      
    6. 我们将在触发PointerEntered 事件时禁用ScrollViewer。在这一步中,我们还将记住按下的PointerPoint——因为我们禁用了Scrollviewer,我们将不得不手动滚动它——这就是我们需要这个PointerPoint的原因。

      private void myList_PointerEntered(object sender, PointerRoutedEventArgs e)
      {
          firstPoint = e.GetCurrentPoint(myList);
          if (listScrollviewer == null) listScrollviewer = DisableScrolling(myList);
      }
      
    7. 最后是我们的PointerMoved 事件,现在将被触发,因为我们禁用了ScrollViewer - 移动ScrollViewer + 其他你需要放在那里的代码:

      private void myList_PointerMoved(object sender, PointerRoutedEventArgs e)
      {
          if (listScrollviewer != null)
          {
              PointerPoint secondPoint = e.GetCurrentPoint(myList);
              double verticalDifference = secondPoint.Position.Y - firstPoint.Position.Y;
              listScrollviewer.ChangeView(null, listScrollviewer.VerticalOffset - verticalDifference, null);
          }
          // some other code you need
      }
      

    几点说明:

    • 此方法仍需要大量调整,但希望能向您展示如何实现您的目标,
    • 您可能还需要将一些小的水平运动与垂直运动分开,
    • 如果您的ListView 或其他控件有水平滚动,那么您还需要禁用并处理它,
    • 这种方法可能不会像原来的ScrollViewer 那样顺利。

    我还提供了一个简单的工作示例here at OneDrive。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 2011-05-26
      相关资源
      最近更新 更多