[WPF自定义控件库] 关于ScrollViewer和滚动轮劫持(scroll-wheel-hijack)
原文:[WPF自定义控件库] 关于ScrollViewer和滚动轮劫持(scroll-wheel-hijack)
1. 什么是滚动轮劫持#
这篇文章介绍一个很简单的继承自ScrollViewer的控件:
Copypublic class ExtendedScrollViewer : ScrollViewer
{
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (ViewportHeight + VerticalOffset >= ExtentHeight && e.Delta <= 0)
return; if (VerticalOffset == 0 && e.Delta >= 0)
return; base.OnMouseWheel(e);
}
}
所有代码就这么多,这个ExtendedScrollViewer 只是用来解决滚动轮劫持(scroll-wheel-hijack)的问题。所谓的滚动轮劫持,简单来说即是在一个可以滚动的页面使用鼠标滚轮滚动页面的过程中鼠标进入某个可以滚动的子元素导致只在这个子元素中滚动而整个页面想滚滚不动了。
具体看看这个例子:
这个情况相信很多人都遇到过,滚轮被“劫持”后索性去拖动滚动条。有次我遇到个内嵌了很多ScrollViewer的长页面,使用起来真的很恼人,所以我使用ExtendedScrollViewer 解决了这个问题。当然还有另外很多种情况的滚动轮劫持,也有很多解决方案,这篇文章只介绍我遇到的情况和我的解决方案。
2. 实现#
在WPF中要禁止ScrollViewer捕获鼠标滚动时间,可以重写OnMouseWheel
成一个空的方法:
Copyprotected override void OnMouseWheel(MouseWheelEventArgs e)
{
}
OnMouseWheel方法用于响应鼠标滚轮的事件,将它重载成空方法即不再处理鼠标滚利事件。注意在这种情况下不可以使用e.Handled = true
,因为我们的目标是让外层的ScrollViewer可以接收到鼠标滚轮事件,所以不能更改MouseWheelEventArgs 的Handled。
当然我们不满足于无脑禁用鼠标滚轮,我们应该更智能些,先让ScrollViewer滚到底,再交由外层的ScrollViewer滚下去。这里面用到几个属性:
MouseWheelEventArgs中的Delta表示鼠标滚轮的变更量,当这个值为正数时表示滚轮向上。
ExtentHeight,获取ScrollViewer内容的实际高度。
ViewportHeight,获取当前可视区域的高度。
VerticalOffset,包含滚动内容对应于页首的垂直偏移量的值,有效值介于 0 与 ExtentHeight 减去 ViewportHeight 所得的数值之间。
熟悉了上面几个属性的作用后我们可以更好地控制鼠标滚轮的行为,当鼠标向上滚动时,判断现在是否已经滚到顶了,如果是就不处理鼠标滚轮事件:
Copyif (VerticalOffset == 0 && e.Delta >= 0)
return;
而当鼠标向下滚动时,需要根据ViewportHeight
、VerticalOffset
和ExtentHeight
判断当前是否已经滚动到底,如果是就不处理鼠标滚轮事件:
Copyif (ViewportHeight + VerticalOffset >= ExtentHeight && e.Delta <= 0)
return;
3. 其他ScrollViewer方案#
ScrollViewer还有很多中玩法,但我工作中不常用到所以就没做。如果觉得不满足还可以参考HandyControl的ScrollViewer,它直接提供了一个CanMouseWheel
属性用于控制是否响应鼠标滚轮,另外还支持了滚动等功能。
4. 参考#
ScrollViewer.OnMouseWheel(MouseWheelEventArgs) Method (System.Windows.Controls) Microsoft Docs
MouseWheelEventArgs.Delta Property (System.Windows.Input) Microsoft Docs
ScrollViewer.ExtentHeight Property (System.Windows.Controls) Microsoft Docs
ScrollViewer.ViewportHeight Property (System.Windows.Controls) Microsoft Docs
ScrollViewer.VerticalOffset Property (System.Windows.Controls) Microsoft Docs
5. 源码#
ExtendedScrollViewer.cs at master
[WPF自定义控件库] 关于ScrollViewer和滚动轮劫持(scroll-wheel-hijack)的更多相关文章
- [WPF自定义控件库] 关于ScrollViewr和滚动轮劫持(scroll-wheel-hijack)
1. 什么是滚动轮劫持 这篇文章介绍一个很简单的继承自ScrollViewer的控件: public class ExtendedScrollViewer : ScrollViewer { prote ...
- WPF 如何创建自己的WPF自定义控件库
在我们平时的项目中,我们经常需要一套自己的自定义控件库,这个特别是在Prism这种框架下面进行开发的时候,每个人都使用一套统一的控件,这样才不会每个人由于界面不统一而造成的整个软件系统千差万别,所以我 ...
- [WPF自定义控件库]使用WindowChrome自定义RibbonWindow
原文:[WPF自定义控件库]使用WindowChrome自定义RibbonWindow 1. 为什么要自定义RibbonWindow 自定义Window有可能是设计或功能上的要求,可以是非必要的,而自 ...
- [WPF自定义控件库] 让Form在加载后自动获得焦点
原文:[WPF自定义控件库] 让Form在加载后自动获得焦点 1. 需求 加载后让第一个输入框或者焦点是个很基本的功能,典型的如"登录"对话框.一般来说"登录" ...
- [WPF自定义控件库]以Button为例谈谈如何模仿Aero2主题
1. 为什么选择Aero2 除了以外观为卖点的控件库,WPF的控件库都默认使用"素颜"的外观,然后再提供一些主题包.这样做的最大好处是可以和原生控件或其它控件库兼容,而且对于大部分 ...
- [WPF自定义控件库]自定义Expander
1. 前言 上一篇文章介绍了使用Resizer实现Expander简单的动画效果,运行效果也还好,不过只有展开/折叠而缺少了淡入/淡出的动画(毕竟Resizer模仿Expander只是附带的功能).这 ...
- [WPF自定义控件库]简单的表单布局控件
1. WPF布局一个表单 <Grid Width="400" HorizontalAlignment="Center" VerticalAlignment ...
- [WPF自定义控件库]了解如何自定义ItemsControl
1. 前言 对WPF来说ContentControl和ItemsControl是最重要的两个控件. 顾名思义,ItemsControl表示可用于呈现一组Item的控件.大部分时候我们并不需要自定义It ...
- [WPF自定义控件库]使用WindowChrome的问题
1. 前言 上一篇文章介绍了使用WindowChrome自定义Window,实际使用下来总有各种各样的问题,这些问题大部分都不影响使用,可能正是因为不影响使用所以一直没得到修复(也有可能别人根本不觉得 ...
随机推荐
- Ldap 从入门到放弃(一)
OpenLDAP 2.4版本 快速入门 本文内容是自己通过官网文档.网络和相关书籍学习和理解并整理成文档,其中有错误或者疑问请在文章下方留言. 一.Introduction to OpenLDAP D ...
- 【GDOI2016模拟4.22】总结
前言 早上,一进机房,发现所有人神情严肃,一股(\(da\))(\(ba\))场的气氛迎面扑来,我一下子意识到:nothing good! 这场比赛结果不是很好,50分: 第一题:感觉上是个神奇的匹配 ...
- linux运维、架构之路-MySQL日志(三)
一.MySQL日志 1.错误日志 ①配置方法 [mysqld] log-error=/data/mysql/mysql.log ②查看配置方式 mysql> show variables lik ...
- Sql server时间转时间long
DATEDIFF( S, '1970-01-01 00:00:00', a.endor_date ) - 8 * 60*60 ) actionTime, SELECT DATEADD(S,116070 ...
- 2017南宁网络赛 Problem J Minimum Distance in a Star Graph ( 模拟 )
题意 : 乱七八糟说了一大堆,实际上就是问你从一个序列到另个序列最少经过多少步的变化,每一次变化只能取序列的任意一个元素去和首元素互换 分析 : 由于只能和第一个元素去互换这种操作,所以没啥最优的特别 ...
- js判断浏览器的类型
我们很多时候都需要判断浏览器,下面就是一些常用的判断 var ua = navigator.userAgent.toLowerCase(); //用来判断移动端类型 var isWeixin = /M ...
- Qt 中文问题
Qt windows/linux跨平台中文编码解决 系统环境:windows8.1 / ubuntu 14.04Qt5.4.2 QtCreator 3.4.1 编码设置:QtCreator:工具/选项 ...
- [HDU6403]:Card Game(dfs+DP+基环树)
题目传送门 题目描述 她依然在我不知道的地方做我不知道的事.桌面上摊开着一些卡牌,这是她平时很爱玩的一个游戏.如今卡牌还在,她却不在我身边.不知不觉,我翻开了卡牌,回忆起了当时一起玩卡牌的那段时间.每 ...
- Seaborn 绘图代码
seaborn单变量.多变量及回归分析绘图 https://blog.csdn.net/llh_1178/article/details/78147822 Python数据科学分析速查表 https: ...
- fengmiantu3