WPF中对滚动条进行平滑滚动

有时候我们在动态添加内容时,需要将滚动条滚动到指定内容处。

一般我们会调用ScrollViewerScrollToVerticalOffset (垂直方向)函数和ScrollToHorizontalOffset(水平方向)函数来控制滚动条滚动到指定位置。

正常滚动效果

例如我们界面上有一个ListBox,我们想让滚动条滚动到指定项

XAML

复制代码
 1 <Grid>
 2     <Grid.RowDefinitions>
 3         <RowDefinition/>
 4         <RowDefinition Height="35"/>
 5     </Grid.RowDefinitions>
 6 
 7     <ScrollViewer VerticalScrollBarVisibility="Auto" Name="scroll">
 8         <ListBox Name="list" Background="Transparent"></ListBox>
 9     </ScrollViewer>
10 
11     <Button Content="普通滚动" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="88" Click="Button_Click" Margin="-120,0,0,0"></Button>
12     <Button Content="平滑滚动" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="88" Click="Button_Click_1" Margin="120,0,0,0"></Button>
13 </Grid>

.cs

复制代码
 1 //随机选中一项 
 2 Random r = new Random();
 3 var item = this.list.Items[r.Next(0, 50)];
 4 
 5 ListBoxItem listBoxItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
 6 
 7 // 获取选择元素的位置
 8 Point position = listBoxItem.TranslatePoint(new Point(0, 0), list);
 9 
10 
11 //滚动到指定位置
12 this.scroll.ScrollToVerticalOffset(position.Y);
13 this.list.SelectedItem = item;

说明:ListBox提供了一个ScrollIntoView函数可以滚动到指定项,但是直接调用ScrollViewer的函数可以适用于所有出现滚动条的场景。

运行效果如下:

平滑滚动

一开始我想的是通过一个循环,缓动增加Y的位置,这样就达到了动画效果。这种方案是可行的,示例代码如下

复制代码
 1 Random r = new Random();
 2 var item = this.list.Items[r.Next(0, 50)];
 3 
 4 ListBoxItem listBoxItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
 5 
 6 // 获取选择元素的位置
 7 Point position = listBoxItem.TranslatePoint(new Point(0, 0), list);
 8 
 9 var gap = position.Y - this.scroll.VerticalOffset;
10 
11 //假设分5次
12 var tick = (int)(gap / 5);
13 int y = (int)this.scroll.VerticalOffset;
14 
15 for (int i = 0; i < 5; i++)
16 {
17     y += tick;
18     this.scroll.ScrollToVerticalOffset(y);
19     //缓慢滚动到指定位置
20     await Task.Delay(50);
21 }
22 
23 this.scroll.ScrollToVerticalOffset(position.Y);
24 
25 this.list.SelectedItem = item;

我们也可以借助WPF的Animation来做,这样效果会更好。

实现原理如下:

1、新建一个辅助类,里面定义一个附加属性

2、当这个附加属性的值更新时,我们去调用ScrollToVerticalOffset进行滚动

3、用ScrollViewer对这个附加属性进行动画

1、定义附加属性

复制代码
1 public static class ScrollViewerHelper
2 {
3     public static readonly DependencyProperty VerticalOffsetProperty =
4         DependencyProperty.RegisterAttached(
5             "VerticalOffset",
6             typeof(double),
7             typeof(ScrollViewerHelper),
8             new PropertyMetadata(0.0, OnVerticalOffsetChanged));
9 }

2、当附加属性值更新时,调用ScrollToVerticalOffset进行滚动

复制代码
1  private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
2  {
3      if (d is ScrollViewer scrollViewer)
4      {
5          scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
6      }
7  }

3、用ScrollViewer对这个附加属性进行动画

复制代码
 1 DoubleAnimation animation = new DoubleAnimation
 2 {
 3     From = scrollViewer.VerticalOffset,
 4     To = targetOffset,
 5     Duration = TimeSpan.FromSeconds(durationInSeconds),
 6     EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut }
 7 };
 8 
 9 animation.Completed += (s, e) => scrollViewer.ScrollToVerticalOffset(targetOffset);
10 
11 scrollViewer.BeginAnimation(ScrollViewerHelper.VerticalOffsetProperty, animation);

演示效果

这里还可以进行一定的优化,可以让选中项始终居中。

示例代码

下载

相关推荐
zizisuo14 小时前
9.1.领域驱动设计
wpf
大道随心14 小时前
【wpf】10 C#树形控件高效实现:递归构建与路径查找优化详解
开发语言·c#·wpf
离歌漠17 小时前
WPF内嵌其他进程的窗口
c#·wpf
沉到海底去吧Go1 天前
【身份证识别表格】批量识别身份证扫描件或照片保存为Excel表格,怎么大批量将身份证图片转为excel表格?基于WPF和腾讯OCR的识别方案
ocr·wpf·excel·身份证识别表格·批量扫描件身份证转表格·图片识别表格·图片识别excel表格
csdn_aspnet1 天前
WPF 性能 UI 虚拟化 软件开发人员的思考
ui·wpf
冰茶_1 天前
WPF之绑定模式深入
学习·microsoft·微软·c#·wpf·绑定模式
Vae_Mars1 天前
WPF中如何自定义控件
wpf
冰茶_1 天前
WPF之集合绑定深入
microsoft·微软·c#·wpf·mvvm·数据绑定·布局系统
凌霜残雪2 天前
WPF 3D图形编程核心技术解析
3d·wpf
△曉風殘月〆2 天前
WPF MVVM入门系列教程(五、命令和用户输入)
wpf·mvvm