c# MouseWheel Scroll 和 RTB VScroll 事件

Posted

技术标签:

【中文标题】c# MouseWheel Scroll 和 RTB VScroll 事件【英文标题】:c# MouseWheel Scroll and RTB VScroll Event 【发布时间】:2011-12-05 18:45:52 【问题描述】:

我有点困惑:

如果用户向上滚动,我们有一个聊天应用程序要求不滚动聊天;我们有一个 scrollInfo 类,它为我们提供了检查滚动条拇指是否位于滚动条底部的能力,以便我们确定是否应该滚动。

不幸的是,滚动聊天有很多不同的方式。可以使用向上/向下滚动条框,或滚动条拇指,或者只使用鼠标滚轮滚动。

但是,如果使用向上/向下箭头,我们没有问题。

而且,如果使用滚动条拇指,VScroll 事件确实会触发,但我们无法确定拇指移动到哪个方向,或者如何检查它是否被按住,而不使用计时器不断查询鼠标左键状态。

最后,如果鼠标滚轮被滚动,虽然我们可以通过查看Delta 属性来判断它的方向,但在处理鼠标滚轮事件后,VScroll 事件仍然会触发。所以,我们基本上发生了重复滚动。

我需要一些帮助。我们的聊天应用如下:

.NET 4.0 Windows 窗体 C# 应用程序 内置于 Visual Studio 2010 *聊天输出:* RichTextBox 自动格式化输入的文本。

这是我们的逻辑的一个示例,但它不起作用:

    用户使用鼠标滚轮向上滚动:当新消息进入时,他们不应向下滚动聊天输出框。相反,当滚动事件发生时,它应该能够检测到滚动拇指的位置,并做出决定。

    用户使用 ScrollBar thumb 向上滚动:触发 VScroll 事件,该事件检查滚动条是否位于滚动框的“底部”。并且,如果是,它会执行完整滚动事件,以确保插入符号始终放置在滚动框的末尾,并且是隐藏的(因此 READ ONLY 聊天输出,没有实际闪烁的 I 光束)。

    用户使用滚动条上/下箭头滚动:工作正常。 (无需解释,因为它已经在工作了)。

我需要在这里澄清一下,我怎样才能正确检查这些事件?

-------- 编辑澄清 --------- scrollInfo类的内容:

 internal class Scrollinfo

    internal const uint ObjidVscroll = 0xFFFFFFFB;

    [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetScrollBarInfo")]
    private static extern int GetScrollBarInfo(IntPtr hWnd,
                                               uint idObject,
                                               ref Scrollbarinfo psbi);

    internal static bool CheckBottom(Control rtb, int postion)
    
        var info = new Scrollbarinfo();
        info.CbSize = Marshal.SizeOf(info);

        var chk = GetScrollBarInfo(rtb.Handle,
                                   ObjidVscroll,
                                   ref info);
        if (chk == 0)
            GetScrollBarInfo(rtb.Handle,
                             ObjidVscroll,
                             ref info);


        bool isbottom = info.XyThumbBottom
                        >= (info.RcScrollBar.Bottom - info.RcScrollBar.Top - (info.DxyLineButton + 1));
        if (info.DxyLineButton <= 0) isbottom = true;
        if (info.XyThumbBottom <= 0) isbottom = true;
        return isbottom;
    




internal struct Scrollbarinfo

    internal int CbSize;
    internal Rect RcScrollBar;
    internal int DxyLineButton;
    internal int XyThumbTop;
    internal int XyThumbBottom;
    internal int Reserved;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    internal int[] Rgstate;


internal struct Rect

    internal int Left;
    internal int Top;
    internal int Right;
    internal int Bottom;

【问题讨论】:

同样让我们感到困惑的是,如果用户使用鼠标滚轮向上滚动,VScroll 事件会按预期触发,但它仍会记录滚动拇指位于底部;而不是注册它已向上滚动。我认为这样做是因为VScroll 没有在事件之后触发,而是在事件期间触发,并且滚动拇指还没有改变位置。因此,我们遇到了滚动问题。 您在谈论“scrollinfo”类而没有解释它的作用。听起来像是坏了。在 VScroll 事件中使用 GetCharIndexFromPosition 和 GetLineFromCharIndex 来找出用户正在看到的内容。 我添加了scrollinfo的内容,这样你就可以看到它的作用了。 【参考方案1】:

你可以试试这样的:

使用要显示的新文本更新框,然后使用以下代码找到最后一个可见行:

rtb.GetLineFromCharIndex(rtb.GetCharIndexFromPosition(新点(rtb.Width, rtb.Height)));

现在下次您需要将文本放入 RichTextBox 时,只需使用与上述相同的代码检查最后一个可见行。

如果新的最后可见行小于旧行,则表示用户向上滚动(或 RichTextBox 已调整大小)。无论哪种情况,您只需将插入符号移到文本末尾,然后调用RichTextBox.ScrollToCaret() 方法即可恢复位置。

我还建议您查看 MSDN 网站上的以下内容:

RichTextBox Methods RichTextBox.GetCharIndexFromPosition Method RichTextBox.GetLineFromCharIndex Method RichTextBox.Select Method¹ RichTextBox.ScrollToCaret Method

¹这可用于设置插入符号的位置。

【讨论】:

非常感谢,这是最有意义的。你得到了赏金:)

以上是关于c# MouseWheel Scroll 和 RTB VScroll 事件的主要内容,如果未能解决你的问题,请参考以下文章

Added non-passive event listener to a scroll-blocking 'mousewheel' event. Consider marking e

firefox滚动参数

使用 MouseWheel c# winform 图表水平滚动

使用带有滚动条的任何控件时不会触发 MouseWheel 事件(在 C# Windows 窗体中)

c#如何设置panel的鼠标滑轮事件?MouseWheel只能应用于Form吗?

滚轮事件来写懒加载