简体   繁体   English

禁用 Richtextbox 上的平滑滚动

[英]Disabling Smooth Scrolling on Richtextbox

I have a label which labels the line numbers based on the text on RichTextBox.我有一个标签,它根据 RichTextBox 上的文本标记行号。 I have hooked the event of Vscroll to handle the labeling.我已经挂钩了 Vscroll 的事件来处理标签。

private void rtbLogicCode_VScroll(object sender, EventArgs e)
{
    Point pt = new Point(0, 1);
    int firstIndex = rtbLogicCode.GetCharIndexFromPosition(pt);
    int firstLine = rtbLogicCode.GetLineFromCharIndex(firstIndex);

    pt.X = ClientRectangle.Width;
    pt.Y = ClientRectangle.Height;
    int lastIndex = rtbLogicCode.GetCharIndexFromPosition(pt);
    int lastLine = rtbLogicCode.GetLineFromCharIndex(lastIndex);

    // Small correction
    if (rtbLogicCode.Text.EndsWith("\n"))
        lastLine++;

    labelLogicCode.ResetText();
    LabelLineNum(firstLine+1,lastLine);
}
#endregion

private void LabelLineNum(int startNum, int lastNum)
{
    labelLogicCode.Font = UIConstant.DDCLogicCodeFont;
    for (int i = startNum; i < lastNum; i++)
    {
        labelLogicCode.Text += i + Environment.NewLine;
    }
}

Everything seems to work properly except RichTextBox uses Smooth Scrolling feature, which screws up my line numbering in many cases where the user has not scrolled all the way to the next line.除了 RichTextBox 使用平滑滚动功能之外,一切似乎都正常工作,在许多情况下,当用户没有一直滚动到下一行时,它会搞砸我的行号。 This causes the line numbers to be not synchronized with the actual text shown on the RichTextBox.这会导致行号与 RichTextBox 上显示的实际文本不同步。

In the end, I need to disable smoothscrolling feature to accomplish this.最后,我需要禁用平滑滚动功能来完成此操作。 I was told that you can override the postMessage API of RichTextBox to disable the mentioned feature but after searching through many documents, I couldn't find any good ones.有人告诉我,您可以覆盖 RichTextBox 的 postMessage API 以禁用上述功能,但是在搜索了许多文档后,我找不到任何好的文档。

I would appreciate a solution that is as detailed as possible on how to disable smoothscrolling feature.我希望有一个关于如何禁用平滑滚动功能的尽可能详细的解决方案。 Thanks.谢谢。

Here's a VB example from Microsoft, suggesting you need to intercept WM_MOUSEWHEEL messages.这是微软的一个VB 示例,建议您需要拦截WM_MOUSEWHEEL消息。

Here's a quick prototype in C#:这是 C# 中的一个快速原型:

class MyRichTextBox : RichTextBox {

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessage(
          IntPtr hWnd,      // handle to destination window
          uint Msg,       // message
          IntPtr wParam,  // first message parameter
          IntPtr lParam   // second message parameter
    );

    const uint WM_MOUSEWHEEL = 0x20A;
    const uint WM_VSCROLL = 0x115;
    const uint SB_LINEUP = 0;
    const uint SB_LINEDOWN = 1;
    const uint SB_THUMBTRACK = 5;

    private void Intercept(ref Message m) {
        int delta = (int)m.WParam >> 16 & 0xFF;
        if((delta >> 7) == 1) {
            SendMessage(m.HWnd, WM_VSCROLL, (IntPtr)SB_LINEDOWN, (IntPtr)0);
        } else {
            SendMessage(m.HWnd, WM_VSCROLL, (IntPtr)SB_LINEUP, (IntPtr)0);
        }
    }

    protected override void WndProc(ref Message m) {
        switch((uint)m.Msg) {
            case WM_MOUSEWHEEL:
                Intercept(ref m);
                break;
            case WM_VSCROLL:
                if(((uint)m.WParam & 0xFF) == SB_THUMBTRACK) {
                    Intercept(ref m);
                } else {
                    base.WndProc(ref m);
                }
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }
}

I know this is old, but if Dan Sporici's site ever goes down I thought I post his fantastic solution.我知道这已经过时了,但是如果 Dan Sporici 的网站出现故障,我想我会发布他出色的解决方案。 It's simple and works easily with just a copy & paste.它很简单,只需复制和粘贴即可轻松工作。

class editedRichTextBox : RichTextBox
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

    //this message is sent to the control when we scroll using the mouse
    private const int WM_MOUSEWHEEL = 0x20A;

    //and this one issues the control to perform scrolling
    private const int WM_VSCROLL = 0x115;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_MOUSEWHEEL)
        {
            int scrollLines = SystemInformation.MouseWheelScrollLines;
            for (int i = 0; i < scrollLines; i++)
            {
                if ((int)m.WParam > 0) // when wParam is greater than 0
                    SendMessage(this.Handle, WM_VSCROLL, (IntPtr)0, IntPtr.Zero); // scroll up 
                else  
                    SendMessage(this.Handle, WM_VSCROLL, (IntPtr)1, IntPtr.Zero); // else scroll down
            }
            return;
        }
        base.WndProc(ref m);
    }
}

This will solve for VB.NET as well as C# (use code converter).这将解决 VB.NET 以及 C#(使用代码转换器)。

  1. Just paste this code outside your own class (Eg: Public Class Form1).只需将此代码粘贴到您自己的类之外(例如:Public Class Form1)。
  2. Run the code once and new control will be added to the toolbox.运行代码一次,新控件将添加到工具箱中。
  3. Now add the control to your FORM from the toolbox in IDE.现在从 IDE 的工具箱中将控件添加到您的FORM中。

Code:代码:

Public Class MyRichTextBox : Inherits RichTextBox
<System.Runtime.InteropServices.DllImport("user32.dll")> Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
    If m.Msg = &H20A Then : Dim ud As IntPtr
        If m.WParam.ToInt32 > 0 Then ud = 0 Else ud = 1
        For i = 1 To 3 : SendMessage(Me.Handle, &H115, ud, 0) : Next
    Else : MyBase.WndProc(m) : End If
End Sub
End Class

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM