WPF 控件库——带有惯性的ScrollViewer
WPF 控件库系列博文地址:
一、先看看效果

二、原理
虽然效果很简单,但是网上的一些资料涉及的代码量非常可观,而且效果也不是很理想,滚动的时候没有一个顺滑感。我这里提供的源码一共120多行,就能实现上图的效果。
本质上我们只要接管ScrollViewer的滚动逻辑,并且把这个逻辑替换成带有惯性的即可,那么如何去接管呢?这里的关键是先屏蔽ScrollViewer的鼠标滚轮事件:
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
e.Handled = true;
}
这样一来,ScrollViewer就不会响应滚轮事件了,我们就在这里做文章。首先我们给这个ScrollViewer添加一个属性 IsEnableInertia ,用来控制是否使用惯性,因为萝卜青菜各有所爱,不要想着强制所有人使用惯性,所以滚轮响应方法变为:
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (!IsEnableInertia)
{
base.OnMouseWheel(e);
return;
}
e.Handled = true;
}
控制ScrollViewer的垂直滚动可以使用 ScrollViewer.ScrollToVerticalOffset ,横向也一样。为什么不能用 VerticalOffset ?因为 VerticalOffset 在注册的时候就说明了是只读的:
private static readonly DependencyPropertyKey VerticalOffsetPropertyKey = DependencyProperty.RegisterReadOnly(nameof (VerticalOffset), typeof (double), typeof (ScrollViewer), (PropertyMetadata) new FrameworkPropertyMetadata((object) 0.0)); public static readonly DependencyProperty VerticalOffsetProperty = ScrollViewer.VerticalOffsetPropertyKey.DependencyProperty;
好了,接下来就是怎么在滚轮响应方法中实现惯性运动了,也就是一种减速运动。想到这儿,熟悉动画的博友很快就知道要用WPF的动画来实现了,默认的动画都是一次线性的,要有惯性效果就得用缓动函数,WPF的缓动函数有很多,而 CubicEase 非常适合用来做惯性,它的描述图如下:

图中,横轴表示时间,纵轴表示运动距离。很明显,中间的 EaseOut 模式就是我们想要的。到了这里思路就清晰了,我们可以定义一个属性 CurrentVerticalOffset ,我们会在它上面实现动画,在它的值回调函数中调用 ScrollViewer.ScrollToVerticalOffset 来更新ScrollViewer的滚动位置。当然我们还需要一个私有字段 _totalVerticalOffset ,这个是用来存放ScrollViewer滚动目标位置的,滚轮向下滚动一个单位我们就给它减去一次 e.Delta ,这里的e是滚轮响应方法传进来的参数,每次给它赋值之后,就可以在 CurrentVerticalOffset 上执行动画了: BeginAnimation(CurrentVerticalOffsetProperty, animation) ,需要特别注意的是,当一个依赖属性用了动画改变后,再对其赋值则不会生效,原因是在一个动画到达活动期的终点后,时间线默认会保持其进度,直到其父级的活动期和保持期结束为止。如果想在动画结束后还可以手动更改依赖属性的值,则需要把 FillBehavior 设置为Stop。不过这样又会出现一个问题,一旦动画结束,这个依赖属性又会恢复初始值,所以还要给这个动画订阅一个 Completed 事件,在事件响应方法中为 CurrentVerticalOffset 给定目标值,也就是 _totalVerticalOffset 。
最后还有一个冲突问题,当手动拖动滑块或者当用上下文菜单改变滚动条位置时是不能用动画的,因为这时候没有触发 OnMouseWheel ,没关系,这正是我们想要的,但是如果再次触发 OnMouseWheel 就有问题了,因为手动触发滚动的时候我们没有给 CurrentVerticalOffset 和 _totalVerticalOffset 赋值( CurrentVerticalOffset 和 _totalVerticalOffset 只在 OnMouseWheel 中赋值),所以在用动画执行滚动操作前要先判断一下是否需要先更新一下它们俩,如何判断?我们可以用一个私有字段 _isRunning 来维护状态,每当动画开始就给它赋值true,结束则赋值false。这样一来,当 _isRunning = false 时,说明在调用 OnMouseWheel 前,动画已经结束,用户可能已经手动改变了滚动条位置(也可能没有,但这并不影响),所以就要给之前俩兄弟更新一下值了。
因为常见的惯性滚动以垂直方向居多,所以我没有写水平方向的逻辑,但也很容易扩展,有兴趣的博友可以下载源代码自己研究。
三、源码
本文所讨论的控件源码已经在github开源:https://github.com/NaBian/HandyControl
WPF 控件库——带有惯性的ScrollViewer的更多相关文章
- WPF 控件库——带有惯性的ScrollViewer*(转)
转:https://blog.csdn.net/ahilll/article/details/82418892 一.先看看效果 二.原理 虽然效果很简单,但是网上的一些资料涉及的代码量非常可观,而且效 ...
- WPF 控件库——仿制Windows10的进度条
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- WPF 控件库——仿制Chrome的ColorPicker
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- WPF 控件库——轮播控件
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- WPF 控件库——可拖动选项卡的TabControl
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- 《Dotnet9》系列-开源C# WPF控件库3《HandyControl》强力推荐
大家好,我是Dotnet9小编,一个从事dotnet开发8年+的程序员.我最近开始写dotnet分享文章,希望能让更多人看到dotnet的发展,了解更多dotnet技术,帮助dotnet程序员应用do ...
- 我的WPF控件库——KAN.WPF.XCtrl(141105)
自己开发的WPF控件库,只是初版,有扩展的Button,TextBox,Window.详细参见前几篇博文. WPF自定义控件(一)——Button:http://www.cnblogs.com/Qin ...
- 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程
反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) 背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...
- 国内开源C# WPF控件库Panuon.UI.Silver推荐
国内优秀的WPF开源控件库,Panuon.UI的优化版本.一个漂亮的.使用样式与附加属性的WPF UI控件库,值得向大家推荐使用与学习. 今天站长(Dotnet9,站长网址:https://dotne ...
随机推荐
- 杂项-EMS:目录
ylbtech-杂项-EMS:目录 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 7.返回顶部 8.返回顶部 9.返回顶部 ...
- 【phonegap】用本地浏览器打开网页
<a id="ssl2" href="#" onclick="openLocalExplorer()">请点击跳到页面</ ...
- Flask之性能
5.5 性能 一.不同角度的网站性能 普通用户认为的网站性能 网站性能对于普通用户来说,最直接的体现就是响应时间.用户在浏览器上直观感受到的网站响应速度,即从客户端发送请求,到服务器返回响应内容的时间 ...
- 页面中CSS的四种引入方式的介绍与比较
转自:https://blog.csdn.net/qq_38689666/article/details/79039392 一:行内式 <p style="color:red" ...
- 数据库与vs的连接
新建一个MFC基于对话框的项目后,更改属性, 其中需要将include(里面都是MySQL的头文件)lib是库文件,将.dll放入与.exe同级目录下,或放入系统里(c:\windows\system ...
- ZOJ3953 Intervals
题意 有n个区间,要求删除一些区间使得不存在三个相交的区间.找出删除的最少区间. 分析 是个比较显然的贪心吧. 先按照区间的左起点进行排序,然后从左往右扫,当有三个区间相交的时候,删除那个右端点最远的 ...
- web优化
一个小型的网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单.随着互联网业务的不断丰富,网站相关的技术经过 ...
- dubbo参数调优
dubbo中配置优先级规律:方法级配置优先级高于接口级,consumer的优先级高于provider. 详细: consumer的method配置 > provider的method配置 c ...
- Linux gtypist
一.简介 Typist (gtypist)是一个打字练习软件,用来提升打字的速度. 二.安装 1)源码方式 http://ftp.gnu.org/gnu/gtypist/ 三.使用 http: ...
- xgboost dmatrix中的 weight的重要性
https://stackoverflow.com/questions/35983565/how-is-the-parameter-weight-dmatrix-used-in-the-gradien ...