【问题标题】: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放在这里。
让我们开始吧:
首先 - 您的活动在哪里? - 答案很简单 - 当您启用 ScrollViewer 时,所有事件都会被它拦截并处理。你ListView 只会得到PointerEntered 事件,而在它之后PointerExited,所有进一步的处理都由ScrollViewer 处理。那就是问题所在。但正如我所说,有一种方法可以做你想做的事。
-
为此,假设您仅使用 VerticalScroll 定义了 ListView:
<ListView Name="myList" ScrollViewer.HorizontalScrollMode="Disabled">
当然可以双向进行,但这是一个简单的例子。
-
现在让我们看看Page的构造函数:
PointerPoint firstPoint = null;
ScrollViewer listScrollviewer = null;
public MainPage()
{
this.InitializeComponent();
myList.ItemsSource = yourItemSource;
myList.PointerEntered += myList_PointerEntered;
myList.PointerMoved += myList_PointerMoved;
}
这里没有什么奇怪的 - 我只是订阅事件,并声明两个变量 firstPoint 和 listScrollviewer,我稍后会用到。
-
我们还需要获取我们的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;
}
-
现在 - 要启用我们的事件,我们需要禁用 ScrollViewer:
private ScrollViewer DisableScrolling(DependencyObject depObj)
{
ScrollViewer foundOne = GetScrollViewer(depObj);
if (foundOne != null) foundOne.VerticalScrollMode = ScrollMode.Disabled;
return foundOne;
}
-
我们将在触发PointerEntered 事件时禁用ScrollViewer。在这一步中,我们还将记住按下的PointerPoint——因为我们禁用了Scrollviewer,我们将不得不手动滚动它——这就是我们需要这个PointerPoint的原因。
private void myList_PointerEntered(object sender, PointerRoutedEventArgs e)
{
firstPoint = e.GetCurrentPoint(myList);
if (listScrollviewer == null) listScrollviewer = DisableScrolling(myList);
}
-
最后是我们的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。