11

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

任何人都知道一种方法来覆盖这种行为?

谢谢!

4

3 回答 3

12

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

  1. 备份初始选择
  2. 使控件失焦
  3. 隐藏选择(通过 Windows 消息)
  4. 附加文本
  5. 恢复初始选择
  6. 取消隐藏选择
  7. 重新聚焦控件

您可能还想检查选择是否已经在文本的末尾,如果是,则允许自动滚动行为 - 这基本上模拟了 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();
        }
    }
于 2011-04-18T16:42:43.433 回答
5

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

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

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

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

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

一切顺利!

于 2009-03-09T17:40:27.480 回答
1

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);

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

于 2014-09-15T13:25:46.470 回答