首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >WPF中对滚动条进行平滑滚动

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

作者头像
JusterZhu
发布2025-06-12 12:32:51
发布2025-06-12 12:32:51
4190
举报
文章被收录于专栏:JusterZhuJusterZhu

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

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

正常滚动效果

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

XAML

代码语言:javascript
复制
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="35"/>
    </Grid.RowDefinitions>

    <ScrollViewer VerticalScrollBarVisibility="Auto" Name="scroll">
        <ListBox Name="list" Background="Transparent"></ListBox>
    </ScrollViewer>

    <Button Content="普通滚动" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="88" Click="Button_Click" Margin="-120,0,0,0"></Button>
    <Button Content="平滑滚动" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Width="88" Click="Button_Click_1" Margin="120,0,0,0"></Button>
</Grid>

.cs

代码语言:javascript
复制
//随机选中一项
Random r = new Random();
var item = this.list.Items[r.Next(0, 50)];

ListBoxItem listBoxItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;

// 获取选择元素的位置
Point position = listBoxItem.TranslatePoint(new Point(0, 0), list);


//滚动到指定位置
this.scroll.ScrollToVerticalOffset(position.Y);
this.list.SelectedItem = item;

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

运行效果如下:

图片
图片

平滑滚动

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

代码语言:javascript
复制
Random r = new Random();
var item = this.list.Items[r.Next(0, 50)];

ListBoxItem listBoxItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;

// 获取选择元素的位置
Point position = listBoxItem.TranslatePoint(new Point(0, 0), list);

var gap = position.Y - this.scroll.VerticalOffset;

//假设分5次
var tick = (int)(gap / 5);
int y = (int)this.scroll.VerticalOffset;

for (int i = 0; i < 5; i++)
{
    y += tick;
    this.scroll.ScrollToVerticalOffset(y);
    //缓慢滚动到指定位置
    await Task.Delay(50);
}

this.scroll.ScrollToVerticalOffset(position.Y);

this.list.SelectedItem = item;
图片
图片

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

实现原理如下:

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

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

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

1、定义附加属性

代码语言:javascript
复制
public static class ScrollViewerHelper
{
    public static readonly DependencyProperty VerticalOffsetProperty =
        DependencyProperty.RegisterAttached(
            "VerticalOffset",
            typeof(double),
            typeof(ScrollViewerHelper),
            new PropertyMetadata(0.0, OnVerticalOffsetChanged));
}

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

代码语言:javascript
复制
private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
 {
     if (d is ScrollViewer scrollViewer)
     {
         scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
     }
 }

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

代码语言:javascript
复制
DoubleAnimation animation = new DoubleAnimation
{
    From = scrollViewer.VerticalOffset,
    To = targetOffset,
    Duration = TimeSpan.FromSeconds(durationInSeconds),
    EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut }
};

animation.Completed += (s, e) => scrollViewer.ScrollToVerticalOffset(targetOffset);

scrollViewer.BeginAnimation(ScrollViewerHelper.VerticalOffsetProperty, animation);

演示效果

图片
图片

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

示例代码

https://files-cdn.cnblogs.com/files/zhaotianff/SmoothingScrollViewer.zip?t=1740556904&download=true

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-06-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JusterZhu 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正常滚动效果
  • 平滑滚动
    • 1、定义附加属性
    • 2、当附加属性值更新时,调用ScrollToVerticalOffset进行滚动
    • 3、用ScrollViewer对这个附加属性进行动画
  • 示例代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档