WPF中对滚动条进行平滑滚动
有时候我们在动态添加内容时,需要将滚动条滚动到指定内容处。
一般我们会调用ScrollViewer的ScrollToVerticalOffset(垂直方向)函数和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);
演示效果
这里还可以进行一定的优化,可以让选中项始终居中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构