zoukankan      html  css  js  c++  java
  • WPF实现ScrollViewer滚动到指定控件处

    在前端 UI 开发中,有时,我们会遇到这样的需求:在一个 ScrollViewer 中有很多内容,而我们需要实现在执行某个操作后能够定位到其中指定的控件处;这很像在 HTML 页面中点击一个链接后定位到当前网页上的某个 anchor。

    要实现它,首先我们需要看 ScrollViewer 为我们提供的 API,其中并没有类似于 ScrollToControl 这样的方法;在它的几个以 ScrollTo 开头的方法中,最合适的就是 ScrollToVerticalOffset 这个方法了,这个方法接受一个参数,即纵向的偏移位置。那么,很重要的问题:我们怎么能得到要定位的那个控件在 ScrollViewer 中的位置呢?

    在我之前写的这篇文章中:XAML: 获取元素的位置,有如何获到元素相对位置的介绍,建议大家先了解一下,其中使用了 Visual.TransformToVisual 方法等。当你理解了这篇文章后,再回过头来看本文后面的内容,就很容易了。

    接下来,我们使用以下代码,即可实现上述需求:

    1
    2
    3
    4
    5
    6
    7
    // 获取要定位之前 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 作进一步了解。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    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);
     }
     }
    }

    其使用方法如下:

    1
    2
    3
    4
    5
    6
    7
    <Button>
     <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
      <local:ScrollToControlAction ScrollViewer="{Binding ElementName=s}" TargetControl="{Binding ElementName=txtSectionC}" />
      </i:EventTrigger>
     </i:Interaction.Triggers>
    </Button>

    至此,结合 Action,我们以非常灵活的方式实现了本文所提出的需求。

     源码下载

  • 相关阅读:
    ES6中对象新增方法
    ES6中字符串新增方法
    Laya 吐槽日志.
    汇编与反汇编工具
    Mac 软件下载地址
    红米手机 android4.4.4 root之路
    查看apk安装包信息
    文件搜索
    自动发表QQ空间说说
    批量格式化json
  • 原文地址:https://www.cnblogs.com/sjqq/p/7891346.html
Copyright © 2011-2022 走看看