原文:WPF: 实现 ScrollViewer 滚动到指定控件处
在前端 UI 开发中,有时,我们会遇到这样的需求:在一个 ScrollViewer 中有很多内容,,而我们需要实此刻执行某个操纵后能够定位到此中指定的控件处;这很像在 HTML 页面中点击一个链接后定位到当前网页上的某个 anchor。
要实现它,首先我们需要看 ScrollViewer 为我们供给的 API,此中并没有类似于 ScrollToControl 这样的要领;在它的几个以 ScrollTo 开头的要领中,最合适的就是 ScrollToVerticalOffset 这个要领了,这个要领接受一个参数,即纵向的偏移位置。那么,很重要的问题:我们怎么能得到要定位的阿谁控件在 ScrollViewer 中的位置呢?
在我之前写的这篇文章中:XAML: 获取元素的位置,有如何获到元素相对位置的介绍,建议大家先了解一下,此中使用了 Visual.TransformToVisual 要领等。当你理解了这篇文章后,再回过头来看本文后面的内容,就很容易了。
接下来,我们使用以下代码,即可实现上述需求:
// 获取要定位之前 ScrollViewer 目前的滚动位置 var currentScrollPosition = ScrollViewer.VerticalOffset; var point = new Point(0, currentScrollPosition); // 计算出方针位置并滚动 var targetPosition = TargetControl.TransformToVisual(ScrollViewer).Transform(point); ScrollViewer.ScrollToVerticalOffset(targetPosition.Y);
此外,由于凡是情况下,我们会给与 MVVM 模式,因此我们可以将上述代码封装成一个 Action,而制止在 Code-Behind 代码文件中添加上述代码。
新创建的名为 ScrollToControlAction 的 Action,在此中界说两个依赖属性 ScrollViewer 和 TargetControl,分袂暗示指定的要操纵的 ScrollViewer 和要定位到的控件,然后将上述代码放到其 Invoke 要领中即可。由于 Action 并非本文主题,所以这里并不会展开太多的讲解,可以参考以下代码或本文后供给的 Demo 作进一步了解。
namespace ScrollTest { /// <summary> /// 在 ScrollViewer 中定位到指定的控件 /// 说明:目前撑持的是垂直滚动 /// </summary> public class ScrollToControlAction : TriggerAction<FrameworkElement> { public static readonly DependencyProperty ScrollViewerProperty = DependencyProperty.Register("ScrollViewer", typeof(ScrollViewer), typeof(ScrollToControlAction), new PropertyMetadata(null)); public static readonly DependencyProperty TargetControlProperty = DependencyProperty.Register("TargetControl", typeof(FrameworkElement), typeof(ScrollToControlAction), new PropertyMetadata(null)); /// <summary> /// 方针 ScrollViewer /// </summary> public ScrollViewer ScrollViewer { get { return (ScrollViewer)GetValue(ScrollViewerProperty); } set { SetValue(ScrollViewerProperty, value); } } /// <summary> /// 要定位的到的控件 /// </summary> public FrameworkElement TargetControl { get { return (FrameworkElement)GetValue(TargetControlProperty); } set { SetValue(TargetControlProperty, value); } } protected override void Invoke(object parameter) { if (TargetControl == null || ScrollViewer == null) { throw new ArgumentNullException($"{ScrollViewer} or {TargetControl} cannot be null"); } // 查抄指定的控件是否在指定的 ScrollViewer 中 // TODO: 这里只是指定离它比来的 ScrollViewer,并没有继续向上找 var container = TargetControl.FindParent<ScrollViewer>(); if (container == null || container != ScrollViewer) { throw new Exception("The TargetControl is not in the target ScrollViewer"); } // 获取要定位之前 ScrollViewer 目前的滚动位置 var currentScrollPosition = ScrollViewer.VerticalOffset; var point = new Point(0, currentScrollPosition); // 计算出方针位置并滚动 var targetPosition = TargetControl.TransformToVisual(ScrollViewer).Transform(point); ScrollViewer.ScrollToVerticalOffset(targetPosition.Y); } } }
ScrollToControlAction.cs其使用要领如下: