原文:[WPF自定义控件库] 关于ScrollViewer和滚动轮劫持(scroll-wheel-hijack)

1. 什么是滚动轮劫持#

这篇文章介绍一个很简单的继承自ScrollViewer的控件:

Copy
public 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成一个空的方法:

Copy
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
}

OnMouseWheel方法用于响应鼠标滚轮的事件,将它重载成空方法即不再处理鼠标滚利事件。注意在这种情况下不可以使用e.Handled = true,因为我们的目标是让外层的ScrollViewer可以接收到鼠标滚轮事件,所以不能更改MouseWheelEventArgs 的Handled。

当然我们不满足于无脑禁用鼠标滚轮,我们应该更智能些,先让ScrollViewer滚到底,再交由外层的ScrollViewer滚下去。这里面用到几个属性:

MouseWheelEventArgs中的Delta表示鼠标滚轮的变更量,当这个值为正数时表示滚轮向上。

ExtentHeight,获取ScrollViewer内容的实际高度。

ViewportHeight,获取当前可视区域的高度。

VerticalOffset,包含滚动内容对应于页首的垂直偏移量的值,有效值介于 0 与 ExtentHeight 减去 ViewportHeight 所得的数值之间。

熟悉了上面几个属性的作用后我们可以更好地控制鼠标滚轮的行为,当鼠标向上滚动时,判断现在是否已经滚到顶了,如果是就不处理鼠标滚轮事件:

Copy
if (VerticalOffset == 0 && e.Delta >= 0)
return;

而当鼠标向下滚动时,需要根据ViewportHeightVerticalOffsetExtentHeight判断当前是否已经滚动到底,如果是就不处理鼠标滚轮事件:

Copy
if (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)的更多相关文章

  1. [WPF自定义控件库] 关于ScrollViewr和滚动轮劫持(scroll-wheel-hijack)

    1. 什么是滚动轮劫持 这篇文章介绍一个很简单的继承自ScrollViewer的控件: public class ExtendedScrollViewer : ScrollViewer { prote ...

  2. WPF 如何创建自己的WPF自定义控件库

    在我们平时的项目中,我们经常需要一套自己的自定义控件库,这个特别是在Prism这种框架下面进行开发的时候,每个人都使用一套统一的控件,这样才不会每个人由于界面不统一而造成的整个软件系统千差万别,所以我 ...

  3. [WPF自定义控件库]使用WindowChrome自定义RibbonWindow

    原文:[WPF自定义控件库]使用WindowChrome自定义RibbonWindow 1. 为什么要自定义RibbonWindow 自定义Window有可能是设计或功能上的要求,可以是非必要的,而自 ...

  4. [WPF自定义控件库] 让Form在加载后自动获得焦点

    原文:[WPF自定义控件库] 让Form在加载后自动获得焦点 1. 需求 加载后让第一个输入框或者焦点是个很基本的功能,典型的如"登录"对话框.一般来说"登录" ...

  5. [WPF自定义控件库]以Button为例谈谈如何模仿Aero2主题

    1. 为什么选择Aero2 除了以外观为卖点的控件库,WPF的控件库都默认使用"素颜"的外观,然后再提供一些主题包.这样做的最大好处是可以和原生控件或其它控件库兼容,而且对于大部分 ...

  6. [WPF自定义控件库]自定义Expander

    1. 前言 上一篇文章介绍了使用Resizer实现Expander简单的动画效果,运行效果也还好,不过只有展开/折叠而缺少了淡入/淡出的动画(毕竟Resizer模仿Expander只是附带的功能).这 ...

  7. [WPF自定义控件库]简单的表单布局控件

    1. WPF布局一个表单 <Grid Width="400" HorizontalAlignment="Center" VerticalAlignment ...

  8. [WPF自定义控件库]了解如何自定义ItemsControl

    1. 前言 对WPF来说ContentControl和ItemsControl是最重要的两个控件. 顾名思义,ItemsControl表示可用于呈现一组Item的控件.大部分时候我们并不需要自定义It ...

  9. [WPF自定义控件库]使用WindowChrome的问题

    1. 前言 上一篇文章介绍了使用WindowChrome自定义Window,实际使用下来总有各种各样的问题,这些问题大部分都不影响使用,可能正是因为不影响使用所以一直没得到修复(也有可能别人根本不觉得 ...

随机推荐

  1. 【NOIP2013模拟】DY引擎

    题目 BOSS送给小唐一辆车.小唐开着这辆车从PKU出发去ZJU上课了. 众所周知,天朝公路的收费站超多的.经过观察地图,小唐发现从PKU出发到ZJU的所有路径只会有N(2<=N<=300 ...

  2. LeetCode--146--LRU缓存机制(python)

    运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key) 存 ...

  3. Intraweb IIS发布,数据连接问题

    日前,用IW做了小东西,开始用单独的执行程序发布,一切都没有什么问题,但是发布到正式环境中,用windows IIS发布,怎么也获取不了程序所在的物理路径,而后看了万一的博客,试了一下程序能正常运行, ...

  4. Win10 设置系统时间

  5. 跳转控制语句continue

    1 continue的使用场景: 1.1 在循环语句中 注意:离开使用场景的存在是没有意义的 2 continue的作用: 2.1 单层循环对比break,然后总结两者的区别 2.1.1 break ...

  6. Zookeeper w3cschool教程

    1.简介 ZooKeeper是一种分布式协调服务,用于管理大型主机.在分布式环境中协调和管理服务是一个复杂的过程.ZooKeeper通过其简单的架构和API解决了这个问题. ZooKeeper允许开发 ...

  7. CSS3实现图片黑白滤镜居中,hover缩放遮罩的效果

       hover: 在前端开发中经常会遇到项目展示,往往会采用卡片方式来描述.众多网站中,普遍采用CSS3的scale()方法来实现交互. 本文即是利用纯CSS实现图片居中缩放,此类方法各大网站均有应 ...

  8. [CSP-S模拟测试]:array(单调栈)

    题目描述 在放完棋子之后,$dirty$又开始了新的游戏. 现在他拥有一个长为$n$的数组$A$,他定义第$i$个位置的分值为$i−k+1$,其中$k$需要满足: 对于任意满足$k\leqslant ...

  9. MK66FN2M0VLQ18

    NXP Kinetis K66: 180MHz Cortex-M4F MCU, 2MB Flash, 256KB SRAM, Dual USBs (FS + HS), Ethernet, 144-LQ ...

  10. 《HTML5 与 CSS3 基础教程(第 8 版)》

    第 1 章 网页的构造块 文件名和文件夹名 文件名全部使用小写字母,用短横线分隔单词,用 .html 作为扩展名.混合使用大小写字 母会增加访问者输入正确地址以及找到页面的难度 文件夹的名称也应全部用 ...