UWP ScrollViewer - 区分用户滚动和编程滚动
UWP ScrollViewer - Differentiate between user scrolling and programmatic scrolling
我有一个应用程序,当用户到达 ScrollViewer
中的某个地方时,我需要执行某个操作。此操作有时包括以编程方式将 ScrollViewer
滚动到不同的位置。
为了监听用户的滚动动作,我正在监听ScrollViewer
的ViewChanged
事件。问题是,当我从 ViewChanged
事件处理程序中以编程方式滚动时,同一个事件处理程序最终会再次被调用,导致发生不希望的额外滚动。
我尝试创建一个自定义方法来在调用 ScrollViewer.ChangeView()
之前删除事件处理程序,但这似乎没有效果。
谁能想出解决这个问题的方法,或者区分用户滚动操作和我的程序滚动操作的方法吗?
private void MyScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (conditionals)
{
ScrollTo(location);
}
}
private void ScrollTo(double offset)
{
MyScrollViewer.ViewChanged -= MyScrollViewer_ViewChanged;
MyScrollViewer.ChangeView(offset, null, null);
MyScrollViewer.ViewChanged += MyScrollViewer_ViewChanged;
}
遗憾的是,无法确定是什么触发了 ViewChanged
事件。不过这个问题是可以解决的。
问题在于 ChangeView()
是异步的,因此在调用 ChangeView
后立即重新添加事件处理程序为时过早。 ChangeView
将引发一堆 ViewChanged
事件,最后一个事件 e.IsIntermediate == false
;只有发生这种情况时,您才应该重新挂钩事件处理程序。处理此问题的最佳方法可能是使用一个临时事件处理程序等待 e.IsIntermediate == false
然后重新挂钩原始处理程序。
为了防止用户在执行 ChangeView
期间与 ScrollViewer
交互,可以暂时禁用滚动和缩放模式。
最后,如果用户在满足条件时正在操纵 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);
}
我有一个应用程序,当用户到达 ScrollViewer
中的某个地方时,我需要执行某个操作。此操作有时包括以编程方式将 ScrollViewer
滚动到不同的位置。
为了监听用户的滚动动作,我正在监听ScrollViewer
的ViewChanged
事件。问题是,当我从 ViewChanged
事件处理程序中以编程方式滚动时,同一个事件处理程序最终会再次被调用,导致发生不希望的额外滚动。
我尝试创建一个自定义方法来在调用 ScrollViewer.ChangeView()
之前删除事件处理程序,但这似乎没有效果。
谁能想出解决这个问题的方法,或者区分用户滚动操作和我的程序滚动操作的方法吗?
private void MyScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (conditionals)
{
ScrollTo(location);
}
}
private void ScrollTo(double offset)
{
MyScrollViewer.ViewChanged -= MyScrollViewer_ViewChanged;
MyScrollViewer.ChangeView(offset, null, null);
MyScrollViewer.ViewChanged += MyScrollViewer_ViewChanged;
}
遗憾的是,无法确定是什么触发了 ViewChanged
事件。不过这个问题是可以解决的。
问题在于 ChangeView()
是异步的,因此在调用 ChangeView
后立即重新添加事件处理程序为时过早。 ChangeView
将引发一堆 ViewChanged
事件,最后一个事件 e.IsIntermediate == false
;只有发生这种情况时,您才应该重新挂钩事件处理程序。处理此问题的最佳方法可能是使用一个临时事件处理程序等待 e.IsIntermediate == false
然后重新挂钩原始处理程序。
为了防止用户在执行 ChangeView
期间与 ScrollViewer
交互,可以暂时禁用滚动和缩放模式。
最后,如果用户在满足条件时正在操纵 ScrollViewer
,则在调用 ScrollTo()
.
编辑: 在我的实现中,出现了一个问题,由于这些处理程序被调用的次数,事件处理程序被添加了不止一次。为了解决这个问题,我采用了 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);
}