看了看原生UWP的ScrollViewer,滑动很流畅(例如 开始菜单),但是WPF自带的ScrollViewer滚动十分生硬..

突发奇想,今天来实现一个流畅滚动的ScrollViewer.

一、目标

查阅网上的实现方法,要么直接重写控件,要么一堆Storyboard..很是无奈,还有些许bug.

主要目标如下:

1.能够流畅地滚动ScrollViewer   要求:有惯性的物理滚动 而不是 生硬的 内容滚动.

2.在使用动画的过程中,避免多个begin导致卡顿

3.好用(? )

二、准备工作

实现以上目标需要到的几件东西:

1.对于Listbox之类的控件需要先讲滚动方式变为 像素滚动  (若没有的话就可以不设置)

<ListBox
VirtualizingPanel.ScrollUnit = "Pixel"
VirtualizingPanel.VirtualizationMode="Recycling"/>

2.选一种动画使用的 缓动函数 这里推荐使用 CubicEase的EaseOut函数 (优点:接近于惯性滚动  对于CPU比较友好)

3.要对ScrollViewer启用滚动动画 需要自己写依赖属性:

public static class ScrollViewerBehavior
{
public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerBehavior), new UIPropertyMetadata(0.0, OnVerticalOffsetChanged));
public static void SetVerticalOffset(FrameworkElement target, double value) => target.SetValue(VerticalOffsetProperty, value);
public static double GetVerticalOffset(FrameworkElement target) => (double)target.GetValue(VerticalOffsetProperty);
private static void OnVerticalOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) => (target as ScrollViewer)?.ScrollToVerticalOffset((double)e.NewValue);
}

三、编码

    //继承ScrollViewer 通过截获MouseWheel事件控制滚动
public class MyScrollViewer : ScrollViewer
{
//记录上一次的滚动位置
private double LastLocation = ;
//重写鼠标滚动事件
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
double WheelChange = e.Delta;
//可以更改一次滚动的距离倍数 (WheelChange可能为正负数!)
double newOffset = LastLocation - (WheelChange * );
//Animation并不会改变真正的VerticalOffset(只是它的依赖属性) 所以将VOffset设置到上一次的滚动位置 (相当于衔接上一个动画)
ScrollToVerticalOffset(LastLocation);
//碰到底部和顶部时的处理
if (newOffset < )
newOffset = ;
if (newOffset > ScrollableHeight)
newOffset = ScrollableHeight; AnimateScroll(newOffset);
LastLocation = newOffset;
//告诉ScrollViewer我们已经完成了滚动
e.Handled = true;
}
private void AnimateScroll(double ToValue)
{
//为了避免重复,先结束掉上一个动画
BeginAnimation(ScrollViewerBehavior.VerticalOffsetProperty, null);
DoubleAnimation Animation = new DoubleAnimation();
Animation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
Animation.From = VerticalOffset;
Animation.To = ToValue;
//动画速度
Animation.Duration = TimeSpan.FromMilliseconds();
//考虑到性能,可以降低动画帧数
//Timeline.SetDesiredFrameRate(Animation, 40);
BeginAnimation(ScrollViewerBehavior.VerticalOffsetProperty, Animation);
}
}

使用方法:直接创建 <MyScrollViewer/>

如果是在ListBox中,可以通过修改模板的方式,把<ScrollViewer/>换成MyScrollViewer即可.

四、关于性能

按照上述方法实现的功能,CPU占用率基本稳定在10% ,但是要疯狂地上下滑动滚轮的话,25%+   但是动画还是很流畅的

以下有几点可以改进的措施:

滚动的CPU占用不只是对偏移量的一个计算,与你滚动的UI画面内容具有很大的关系

例如大量的图片Image   3D对象    复杂的自定义控件 等等 都需要在滚动时计算并绘制。

你可以尝试以下方法:

1).启用ListBox的虚拟化技术

2).对于图像的绘制,可以通过降低其渲染度(可能会损坏图片质量 特别是低清小图 ),对你的图片对象使用:

RenderOptions.SetBitmapScalingMode(控件对象,BitmapScalingMode.LowQuality);

3).就像上文中所说,可以通过降低渲染帧数来控制CPU占用率(可能会又是流畅度)

4).如果能找到更好的缓动函数

5).参阅: 优化控件性能 -WPF |Microsoft Docs

WPF 如何流畅地滚动ScrollViewer 简单实现下的更多相关文章

  1. VS编程,WPF中两个滚动条 ScrollViewer 同步滚动的一种方法

    原文:VS编程,WPF中两个滚动条 ScrollViewer 同步滚动的一种方法 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/ar ...

  2. WPF自定义控件与样式(6)-ScrollViewer与ListBox自定义样式

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: Scr ...

  3. 【转】WPF自定义控件与样式(6)-ScrollViewer与ListBox自定义样式

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要内容: ScrollViewer的样式拆解及基本样式定义: ListBox集合 ...

  4. Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

    一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...

  5. WPF 超长文本的来回滚动

    原文:WPF 超长文本的来回滚动 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Vblegend_2013/article/details/8362 ...

  6. 不用splitter控件 简单实现对mfc对话框的分割的方法

    不用splitter控件  简单实现对mfc对话框的分割的方法 直接贴上源代码主要部分吧 这个是基于对话框的工程 进行对话框的分割实现 只是相应了三个消息函数,看一下就会明白的 我空间资源里边有现成的 ...

  7. springmvc springJDBC 简单实训银行账户管理系统

    springmvc springJDBC 简单实训银行账户管理系统 1.简单介绍一下,在校时每周结束都会有一次学习总结,简称“实训”,这次实训内容是spring,因为是最近热门框架,我就先从基础方面开 ...

  8. WPF获取外部EXE图标最简单的方法

    原文:WPF获取外部EXE图标最简单的方法 首先在工程添加对System.Drawing的引用 创建以下方法: public static ImageSource GetIcon(string fil ...

  9. WPF MVVM+EF增删改查 简单示例(二) 1对1 映射

    WPF MVVM+EF增删改查 简单示例(一)实现了对学生信息的管理. 现在需求发生变更,在录入学生资料的时候同时需要录入学生的图片信息,并且一名学生只能有一张图片资料.并可对学生的图片资料进行更新. ...

随机推荐

  1. webpack 3 升级 webpack4 个人笔记

    参考文章: 1. webpack4升级完全指南 https://segmentfault.com/a/1190000014247030 2. Mobx useStrict is not a funct ...

  2. xampp-apache配置

    我安装的软件是xampp-win32-1.8.2-0-VC9-installer 需要配置的文件有 httpd.conf httpd-default.conf httpd-info.conf http ...

  3. 苏浪浪 201771010120 《面向对象程序设计(java)》第9周学习总结

    实验九异常.断言与日志 实验时间 2018-10-25 1.实验目的与要求 (1) 掌握java异常处理技术: (2) 了解断言的用法: (3) 了解日志的用途: (4) 掌握程序基础调试技巧: 2. ...

  4. Docker 错误:network xxx id xxxx has active endpoints

    问题描述:Docker Compose 部署的项目,使用docker-compose down 命令关闭时,提示错误: Removing network xxxl_default ERROR: net ...

  5. layui加tp5图片上传实例

    <div class="layui-fluid"> <div class="layui-row"> <form class=&qu ...

  6. 第一章-初识AngularJS

    完全使用javascript编写的客户端技术.同其他历史悠久的Web技术配合使用,使Web应用开发比以往更简单,更快捷. Angularjs主要用于构建单页面Web应该.它通过增加开发人员和常见Web ...

  7. Linux SCP命令远程复制文件

    从本地复制到远程 scp 本地文件 远程用户名@远程地址:远程目录(此命令回车后会要求输入密码,验证通过后会把本地文件复制到远程目录中,文件名不变) 或者 scp 本地文件 远程用户名@远程地址:远程 ...

  8. 学习Pytorch遇到的一些问题(一)

    基本介绍 这周开始学习深度学习的部分知识,参考的书是<动手学深度学习>(PyTorch版),在操作过程中遇到一些小问题,记录一下问题和解决办法. PyTorch下载过慢 安装步骤 PyTo ...

  9. 从 React 架构开始讲解 useState、useEffect 编程设计

    随着前端开发复杂度增加,原生开发模式显得越来越笨重,前端框架也层出不穷. MVC 和 MVVM MVC MVC是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计 ...

  10. 数据分析 | 数据可视化图表,BI工具构建逻辑

    本文源码:GitHub·点这里 || GitEE·点这里 一.数据可视化 1.基础概念 数据可视化,是关于数据视觉表现形式的科学技术研究.其中,这种数据的视觉表现形式被定义为,一种以某种概要形式抽取出 ...