检测ListView

时间:2016-03-25 09:50:03

标签: xaml listview windows-runtime windows-phone-8.1 win-universal-app

通用Windows 8.1存储项目。

我想知道,当ListView在用户交互后停止滚动时。我在网上找到了大量的信息,但没有一个可靠的工作在WP 8.1上的例子(WPF / WP8示例没有多大帮助,并且有很多它们。)

这就是我现在所做的。

1。 ListView

<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。 ScrollViewer

我在后面的代码中从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;
  }
}

这在某种程度上有效。

问题

问题是,ViewChanged当列表被滚动到该端不会触发/启动和用户拉动它出界并释放它,从而引起它与惯性返回回来。因此,检测到交互开始,但结果不是。 ViewChanged根本没有被解雇 - IsIntermediate = True,也不是False。

ViewChanged event is not fired at all

什么是做我想做的更好的方法?

2 个答案:

答案 0 :(得分:2)

可悲的是,除了重复轮询和检查ScrollOffset之外,在Windows 8.1上没有好办法。

我只得到一个10个双打的数组,就像每秒10次我移入当前的滚动偏移量。在同一个处理程序中检查最后5个是否等于列表的结尾而不是引发事件。

答案 1 :(得分:1)

正如TamásDeme所说,没有什么好办法可以做到所需要的。但是,我发现了一个适用于我的情况的解决方法(虽然没什么好看的。)

事实上,当滚动停止时,我正在检测列表是否滚动到底部。它正在检测滚动的结束是导致这么多麻烦的原因。

问题分为两部分: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不同,当事件图片中显示的情况下惯性停止时,此事件也会被触发。不幸的是,没有办法在LayoutUpdated中确定列表是否完全停止滚动。

当您通过滚动实际更改ViewChanged时,

VerticalOffset正常工作; LayoutUpdated涵盖了滚动过度的情况。

还有另一个问题:滚动列表边缘时,OnScrollLayoutUpdated可能会保持订阅状态,因为ViewChanged不会触发。幸运的是,我可以忽略它,这不会破坏任何东西。