专栏首页dino.c的专栏[WPF自定义控件库] 关于ScrollViewr和滚动轮劫持(scroll-wheel-hijack)

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

1. 什么是滚动轮劫持

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

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

protected override void OnMouseWheel(MouseWheelEventArgs e)
{
}

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

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

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

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

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

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

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

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

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

if (ViewportHeight + VerticalOffset >= ExtentHeight && e.Delta <= 0)
    return;

3. 其他ScrollViewer方案

ScrollViewer还有很多中玩法,但我工作中不常用到所以就没做。如果觉得不满足还可以参考HandyControl的ScrollViewer,它直接提供了一个CanMouseWheel属性用于控制是否响应鼠标滚轮,另外还支持了滚动等功能。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

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

    在WPF中布局表单一直都很传统,例如使用上面的XAML,它通过Grid布局一个表单。这样出来的结果整整齐齐,看上去没什么问题,但当系统里有几十个表单页以后需要统...

    dino.c
  • Silverlight自定义鼠标

      http://msdn.microsoft.com/zh-cn/library/system.windows.input.cursor(VS.95).asp...

    dino.c
  • [UWP]做个调皮的BusyIndicator

    最近突然想要个BusyIndicator。做过WPF开发的程序员对BusyIndicator应该不陌生,Extended WPF Toolkit 提供了Busy...

    dino.c
  • WIN7系统如何在本地(局域网)配置PHP环境?

    安装完成后,点击控制面板->管理工具->Internet Information Services (IIS)管理器(注意不是那个什么6.0的)

    V站CEO-西顾
  • 物联网弊端:奥地利旅馆被入侵后的反思

    导语:物联网给我们的生活带来了许多便利——例如,一些镇的集成交通系统——然而物联网也大大提高了网络安全方面的风险。我们应该如何应对这些新的威胁呢? ? Chri...

    企鹅号小编
  • Super快报第28期:看点多多的360财报

    1、奇虎360股价大涨5%创52周新高 奇虎360(NYSE:QIHU)周二股价最新上涨5%,触及52周新高。达到34.53美元。此52周一年奇虎股价上涨超1...

    罗超频道
  • python中的装饰器

    很多时候我们可能会有这样的需求,就是在调试的时候我们会想打印出某些变量出来看看程序对不对,然后在我们调试好了的时候再把这些print语句注释;这样做确实比较麻烦...

    GavinZhou
  • Android开发笔记(一百六十六)H5通过WebView录像上传

    前面的博文《Android开发笔记(一百五十二)H5通过WebView上传图片》介绍了如何拍照上传给网页,不料客户又要求再加个...

    用户4464237
  • CNN卷积神经网络的改进(15年最新paper)

    回归正题,今天要跟大家分享的是一些 Convolutional Neural Networks(CNN)的工作。大家都知道,CNN 最早提出时,是以一定的人眼生...

    深度学习思考者
  • 借Reaper僵尸网络推广免费IP扫描器 然后在IP扫描器里面放个后门

    用户1697231

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动