UWP ScrollViewer - 区分用户滚动和程序化滚动

时间:2016-09-29 13:12:55

标签: c# xaml scroll uwp scrollviewer

我有一个应用程序,当用户到达ScrollViewer中的某个位置时,我需要采取某种操作。此操作有时包括以编程方式将ScrollViewer滚动到其他位置。

为了监控用户的滚动操作,我正在收听ViewChanged的{​​{1}}事件。问题是,当我从ScrollViewer事件处理程序中以编程方式滚动时,同一个事件处理程序最终再次被调用,从而导致不希望的额外滚动。

我尝试在调用ViewChanged之前创建一个自定义方法来删除事件处理程序,但这似乎没有效果。

任何人都可以想出解决此问题的方法,或者将用户的滚动操作与我的程序化操作区分开来吗?

ScrollViewer.ChangeView()

1 个答案:

答案 0 :(得分:0)

遗憾的是,无法确定触发ViewChanged事件的原因。但是可以解决这个问题。

问题是ChangeView()是异步的,因此在调用ChangeView后立即重新添加事件处理程序的时间太早了。 ChangeView会举起一系列ViewChanged个活动,最后一个活动会e.IsIntermediate == false;只有在发生这种情况时才重新挂钩事件处理程序。处理此问题的最佳方法可能是使用等待e.IsIntermediate == false的临时事件处理程序,然后重新挂钩原始处理程序。

为防止用户在执行ScrollViewer期间与ChangeView进行交互,可以暂时禁用滚动和缩放模式。

最后,如果用户在满足条件时操纵ScrollViewer,则在调用ScrollTo()之前,该操作必须为canceled

编辑:在我的实现中,出现了一个问题,因为调用这些处理程序的次数,事件处理程序被多次添加。为了解决这个问题,我采用了here的简单策略。

private void MyScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e) 
{
    if (!conditionals) return;

    if (e.IsIntermediate) 
    {
        var uiElement = MyScrollViewer.Content as UIElement;
        uiElement?.CancelDirectManipulations();
    }

    ScrollTo(location);
}

private void Temporary_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
    if (e.IsIntermediate) return;
    MyScrollViewer.ViewChanged -= Temporary_ViewChanged;
    MyScrollViewer.ViewChanged -= MyScrollViewer_ViewChanged;
    MyScrollViewer.ViewChanged += MyScrollViewer_ViewChanged;

    MyScrollViewer.HorizontalScrollMode = ScrollMode.Enabled;
    MyScrollViewer.VerticalScrollMode = ScrollMode.Enabled;
    MyScrollViewer.ZoomMode = ZoomMode.Enabled;
}

private void ScrollTo(double offset)
{
    MyScrollViewer.ViewChanged -= MyScrollViewer_ViewChanged;
    MyScrollViewer.ViewChanged -= Temporary_ViewChanged;
    MyScrollViewer.ViewChanged += Temporary_ViewChanged;

    MyScrollViewer.HorizontalScrollMode = ScrollMode.Disabled;
    MyScrollViewer.VerticalScrollMode = ScrollMode.Disabled;
    MyScrollViewer.ZoomMode = ZoomMode.Disabled;

    MyScrollViewer.ChangeView(offset, null, null);
}