检测 ListView 中滚动的结束
Detecting the end of scrolling in a ListView
通用Windows 8.1 在此处存储项目。
我想知道,当 ListView 在用户交互后停止滚动时。我在网上找到了很多信息,但没有一个在 WP 8.1 上可靠地工作的例子(WPF/WP8 例子没有多大帮助,而且有很多)。
这是我现在所做的。
1。列表视图
<ListView
x:Name="MessageList"
ItemsSource="{Binding Messages}"
VerticalAlignment="Bottom"
ItemContainerStyle="{StaticResource ChatListViewItemStyle}"
PointerEntered="MessageList_OnPointerEntered"
>
<ListView.ItemTemplate>
<DataTemplate>
<messages:MessageContainer />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
2。滚动查看器
我在后面的代码中从 ListView 获得了一个 ScrollViewer 引用。
// GetChildElement<T>(this DependencyObject root) is a simple extension method of mine
Scroll = MessageList.GetChildElement<ScrollViewer>();
3。 ListViewer.PointerEntered 和 ScrollViewer.ViewChanged
PointerEntered
处理程序用于检测用户交互的开始。当检测到交互时,我订阅 Scroll.ViewChanged
并使用事件的 IsIntermediate
标志来检测列表何时停止滚动(包括惯性)。
void MessageList_OnPointerEntered(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("START MONITORING INTERACTION");
Scroll.ViewChanged += OnViewChangedByUser;
}
void OnViewChangedByUser(object sender, ScrollViewerViewChangedEventArgs e)
{
Debug.WriteLine("WAITING FOR INTERACTION TO END");
if (!e.IsIntermediate) {
Debug.WriteLine("INTERACTION ENDED");
Scroll.ViewChanged -= OnViewChangedByUser;
}
}
这在某种程度上确实有效。
问题
问题是,当列表滚动到 end/start 并且用户将其拉出边界并释放它时,ViewChanged
不会触发,导致它返回 return与惯性。因此,检测到交互开始,但未检测到结束。 ViewChanged
根本不会被触发——无论是 IsIntermediate
=True 还是 False。
做我想做的事情的更好方法是什么?
遗憾的是,除了重复轮询和检查 ScrollOffset 之外,在 Windows 8.1 上没有什么好的方法可以做到这一点。
我只得到一个包含 10 个双精度数的数组,并且每秒 10 次我将移入当前的滚动偏移量。比在同一个处理程序中检查最后 5 个是否等于列表的末尾而不是引发事件。
正如 Tamás Deme 所说,没有什么好的方法可以完成所需的工作。但是,我找到了一种适用于我的情况的解决方法(虽然没有什么好处)。
事实上,我正在检测列表是否滚动到底部,当滚动停止时。它正在检测滚动结束是造成这么多麻烦的原因。
问题分为两部分:1 - 检测用户交互结束,2 - 检测惯性结束。令人惊讶的是,没有解决它们中任何一个的好方法。值得庆幸的是,我真正需要的只是知道滚动(用户驱动或惯性动画)停止时 VerticalOffset
的值。我实际上不必知道用户是否仍然持有该列表。
void MessageList_OnPointerEntered(object sender, PointerRoutedEventArgs e)
{
IsScrolledToLastLine = false; // this is to signal, that the user is
// holding the list, and there must be no
// automatic scrolling, when content is
// added to it.
Debug.WriteLine("[*]START MONITORING INTERACTION");
Scroll.ViewChanged += OnViewChangedByUser;
Scroll.LayoutUpdated += OnScrollLayoutUpdated;
}
void OnScrollLayoutUpdated(object sender, object e)
{
// will trigger multiple times during scrolling
// AND
// will trigger when inertia finally stops
// (regardless of the changes of VerticalOffset)
IsScrolledToLastLine = Scroll.ScrollableHeight == Scroll.VerticalOffset;
Debug.WriteLine("Interaction progress: {0}", IsScrolledToLastLine);
}
void OnViewChangedByUser(object sender, ScrollViewerViewChangedEventArgs e)
{
if (!e.IsIntermediate) {
IsScrolledToLastLine = Scroll.ScrollableHeight == Scroll.VerticalOffset;
Debug.WriteLine("Interaction end: {0}", IsScrolledToLastLine);
Scroll.LayoutUpdated -= OnScrollLayoutUpdated;
Scroll.ViewChanged -= OnViewChangedByUser;
}
}
Scroll.LayoutUpdated
LayoutUpdated
在滚动期间被触发多次。与 ViewChanged
不同的是,在 post 图片中惯性停止时也会触发此事件。遗憾的是,在 LayoutUpdated
中无法确定列表是否完全停止滚动。
ViewChanged
当您实际通过滚动更改 VerticalOffset
时工作正常; LayoutUpdated
涵盖过度滚动的情况。
但还有另一个问题:OnScrollLayoutUpdated
可能会在列表边缘滚动时保持订阅状态,因为 ViewChanged
不会触发。幸运的是,我可以忽略它,这不会破坏任何东西。
通用Windows 8.1 在此处存储项目。
我想知道,当 ListView 在用户交互后停止滚动时。我在网上找到了很多信息,但没有一个在 WP 8.1 上可靠地工作的例子(WPF/WP8 例子没有多大帮助,而且有很多)。
这是我现在所做的。
1。列表视图
<ListView
x:Name="MessageList"
ItemsSource="{Binding Messages}"
VerticalAlignment="Bottom"
ItemContainerStyle="{StaticResource ChatListViewItemStyle}"
PointerEntered="MessageList_OnPointerEntered"
>
<ListView.ItemTemplate>
<DataTemplate>
<messages:MessageContainer />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
2。滚动查看器
我在后面的代码中从 ListView 获得了一个 ScrollViewer 引用。
// GetChildElement<T>(this DependencyObject root) is a simple extension method of mine
Scroll = MessageList.GetChildElement<ScrollViewer>();
3。 ListViewer.PointerEntered 和 ScrollViewer.ViewChanged
PointerEntered
处理程序用于检测用户交互的开始。当检测到交互时,我订阅 Scroll.ViewChanged
并使用事件的 IsIntermediate
标志来检测列表何时停止滚动(包括惯性)。
void MessageList_OnPointerEntered(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("START MONITORING INTERACTION");
Scroll.ViewChanged += OnViewChangedByUser;
}
void OnViewChangedByUser(object sender, ScrollViewerViewChangedEventArgs e)
{
Debug.WriteLine("WAITING FOR INTERACTION TO END");
if (!e.IsIntermediate) {
Debug.WriteLine("INTERACTION ENDED");
Scroll.ViewChanged -= OnViewChangedByUser;
}
}
这在某种程度上确实有效。
问题
问题是,当列表滚动到 end/start 并且用户将其拉出边界并释放它时,ViewChanged
不会触发,导致它返回 return与惯性。因此,检测到交互开始,但未检测到结束。 ViewChanged
根本不会被触发——无论是 IsIntermediate
=True 还是 False。
做我想做的事情的更好方法是什么?
遗憾的是,除了重复轮询和检查 ScrollOffset 之外,在 Windows 8.1 上没有什么好的方法可以做到这一点。
我只得到一个包含 10 个双精度数的数组,并且每秒 10 次我将移入当前的滚动偏移量。比在同一个处理程序中检查最后 5 个是否等于列表的末尾而不是引发事件。
正如 Tamás Deme 所说,没有什么好的方法可以完成所需的工作。但是,我找到了一种适用于我的情况的解决方法(虽然没有什么好处)。
事实上,我正在检测列表是否滚动到底部,当滚动停止时。它正在检测滚动结束是造成这么多麻烦的原因。
问题分为两部分:1 - 检测用户交互结束,2 - 检测惯性结束。令人惊讶的是,没有解决它们中任何一个的好方法。值得庆幸的是,我真正需要的只是知道滚动(用户驱动或惯性动画)停止时 VerticalOffset
的值。我实际上不必知道用户是否仍然持有该列表。
void MessageList_OnPointerEntered(object sender, PointerRoutedEventArgs e)
{
IsScrolledToLastLine = false; // this is to signal, that the user is
// holding the list, and there must be no
// automatic scrolling, when content is
// added to it.
Debug.WriteLine("[*]START MONITORING INTERACTION");
Scroll.ViewChanged += OnViewChangedByUser;
Scroll.LayoutUpdated += OnScrollLayoutUpdated;
}
void OnScrollLayoutUpdated(object sender, object e)
{
// will trigger multiple times during scrolling
// AND
// will trigger when inertia finally stops
// (regardless of the changes of VerticalOffset)
IsScrolledToLastLine = Scroll.ScrollableHeight == Scroll.VerticalOffset;
Debug.WriteLine("Interaction progress: {0}", IsScrolledToLastLine);
}
void OnViewChangedByUser(object sender, ScrollViewerViewChangedEventArgs e)
{
if (!e.IsIntermediate) {
IsScrolledToLastLine = Scroll.ScrollableHeight == Scroll.VerticalOffset;
Debug.WriteLine("Interaction end: {0}", IsScrolledToLastLine);
Scroll.LayoutUpdated -= OnScrollLayoutUpdated;
Scroll.ViewChanged -= OnViewChangedByUser;
}
}
Scroll.LayoutUpdated
LayoutUpdated
在滚动期间被触发多次。与 ViewChanged
不同的是,在 post 图片中惯性停止时也会触发此事件。遗憾的是,在 LayoutUpdated
中无法确定列表是否完全停止滚动。
ViewChanged
当您实际通过滚动更改 VerticalOffset
时工作正常; LayoutUpdated
涵盖过度滚动的情况。
但还有另一个问题:OnScrollLayoutUpdated
可能会在列表边缘滚动时保持订阅状态,因为 ViewChanged
不会触发。幸运的是,我可以忽略它,这不会破坏任何东西。