C# 防止在 RichTextBox 中自动滚动

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/626988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 10:51:34  来源:igfitidea点击:

Prevent Autoscrolling in RichTextBox

c#winformsrichtextbox

提问by goombaloon

I have a readonly data logging window that I implemented using the RichTextBox control. I'd like to be able to disable the autoscrolling that happens when the user clicks in the control so that the user can select a specific log for copy/paste operations or whatever. However, as soon as the user clicks in the RichTextBox, it automatically scrolls to the bottom, making this difficult.

我有一个使用 RichTextBox 控件实现的只读数据记录窗口。我希望能够禁用用户单击控件时发生的自动滚动,以便用户可以选择特定日志进行复制/粘贴操作或其他操作。但是,只要用户在 RichTextBox 中单击,它就会自动滚动到底部,这使得这很困难。

Anyone know a way to override this behavior?

有人知道覆盖这种行为的方法吗?

Thanks!

谢谢!

回答by itsmatt

You might take a look at doing something like this:

你可以看看做这样的事情:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LockWindowUpdate(IntPtr Handle);

then in your method that appends log data (I'm making some assumptions here) you might do something like this:

然后在你附加日志数据的方法中(我在这里做了一些假设)你可能会做这样的事情:

LockWindowUpdate(this.Handle);
int pos = richTextBox1.SelectionStart;
int len = richTextBox1.SelectionLength;
richTextBox1.AppendText(yourText);
richTextBox1.SelectionStart = pos;
richTextBox1.SelectionLength = len;
LockWindowUpdate(IntPtr.Zero);

I did a little test app with a timer that did the append on the richtextbox and it stopped it from scrolling so I could do the text selection. It has some positional issues and isn't perfect, but perhaps it'll help move you toward a solution of your own.

我做了一个带有计时器的小测试应用程序,该应用程序在富文本框上进行附加,并阻止它滚动,因此我可以进行文本选择。它有一些位置问题并且并不完美,但也许它会帮助您找到自己的解决方案。

All the best!

祝一切顺利!

回答by SytS

The RichTextBox control automatically scrolls to the current selection, if the selection is not hidden. RichTextBox.AppendText(), in addition to appending text, also modifies the current selection, and so indirectly triggers the "autoscrolling" behaviour. Note that if RichTextBox.HideSelection is set to true, then the selection would be hidden when the control is not in focus; this explains the behaviour you described, where autoscrolling occurs only when the user clicks in the control. (thereby giving it focus) To prevent this, you need to do the following when appending text:

如果选择未隐藏,RichTextBox 控件会自动滚动到当前选择。RichTextBox.AppendText() 除了附加文本外,还会修改当前选择,从而间接触发“自动滚动”行为。请注意,如果 RichTextBox.HideSelection 设置为 true,则当控件未处于焦点时,选择将隐藏;这解释了您描述的行为,其中仅当用户单击控件时才会发生自动滚动。(从而给它焦点)为了防止这种情况,您需要在附加文本时执行以下操作:

  1. Backup the initial selection
  2. Unfocus the control
  3. Hide selection (through a Windows message)
  4. AppendText
  5. Restore the initial selection
  6. Unhide selection
  7. Refocus the control
  1. 备份初始选择
  2. 取消焦点控制
  3. 隐藏选择(通过 Windows 消息)
  4. 附加文本
  5. 恢复初始选择
  6. 取消隐藏选择
  7. 重新聚焦控制

You may also want to check whether the selection is already at the end of the text, and allow the autoscrolling behaviour if it is - this essentially emulates the behaviour of Visual Studio's Output window. For example:

您可能还想检查所选内容是否已经在文本的末尾,如果是,则允许自动滚动行为 - 这实质上模拟了 Visual Studio 的输出窗口的行为。例如:

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
    const int WM_USER = 0x400;
    const int EM_HIDESELECTION = WM_USER + 63;

    void OnAppend(string text)
    {
        bool focused = richTextBox1.Focused;
        //backup initial selection
        int selection = richTextBox1.SelectionStart;
        int length = richTextBox1.SelectionLength;
        //allow autoscroll if selection is at end of text
        bool autoscroll = (selection==richTextBox1.Text.Length);

        if (!autoscroll)
        {
            //shift focus from RichTextBox to some other control
            if (focused) textBox1.Focus();
            //hide selection
            SendMessage(richTextBox1.Handle, EM_HIDESELECTION, 1, 0);
        }

        richTextBox1.AppendText(text);

        if (!autoscroll)
        {
            //restore initial selection
            richTextBox1.SelectionStart = selection;
            richTextBox1.SelectionLength = length;
            //unhide selection
            SendMessage(richTextBox1.Handle, EM_HIDESELECTION, 0, 0);
            //restore focus to RichTextBox
            if(focused) richTextBox1.Focus();
        }
    }

回答by Orace

SytS's solution has an issue, when some text is "appended", the scroll bar moves such that the selection go to the top of the panel. A solution is to save/restore the scroll position with :

SytS 的解决方案有一个问题,当某些文本被“附加”时,滚动条会移动,这样选择就会到达面板的顶部。一种解决方案是使用以下命令保存/恢复滚动位置:

    [System.Runtime.InteropServices.DllImport("User32.dll")]
    extern static int GetScrollPos(IntPtr hWnd, int nBar);

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);

This solutionis more complete for me.

这个解决方案对我来说更完整。