我有一个应用程序,当用户到达ScrollViewer
中的某个位置时,我需要采取某种操作。此操作有时包括以编程方式将ScrollViewer
滚动到其他位置。
为了监控用户的滚动操作,我正在收听ViewChanged
的{{1}}事件。问题是,当我从ScrollViewer
事件处理程序中以编程方式滚动时,同一个事件处理程序最终再次被调用,从而导致不希望的额外滚动。
我尝试在调用ViewChanged
之前创建一个自定义方法来删除事件处理程序,但这似乎没有效果。
任何人都可以想出解决此问题的方法,或者将用户的滚动操作与我的程序化操作区分开来吗?
ScrollViewer.ChangeView()
答案 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);
}