添加线条时保持文本框滚动位置

本文关键字:滚动 位置 文本 加线条 添加 | 更新日期: 2023-09-27 18:31:12

在我的WinForm应用程序中,我有一个多行文本框控件(uiResults),用于在处理大量项目时报告进度。使用 AppendText 非常适合在每次更新时自动滚动到底部,但如果用户向后滚动以读取一些较旧的数据,我需要关闭自动滚动。如果可能的话,我宁愿远离 P/Invoke 调用。

是否可以检测用户是否在不使用 P/Invoke 的情况下向后滚动?现在,我只检查 SelectionStart 它有效,但需要用户从文本框末尾移动插入符号以停止自动滚动:

if(uiResults.SelectionStart == uiResults.Text.Length)
{
  uiResults.AppendText(result + Environment.NewLine);
}

我的主要问题是,使用 Text 属性追加字符串时,文本框会滚动到开头。我试图通过存储插入符号位置并在更新后重置和滚动到它来解决这个问题,但这会导致当前行移动到底部(当然,因为 ScrollToCaret 滚动不超过显示插入符号所需的距离)。

[Continued from above]
else
{
  int pos = uiResults.SelectionStart;
  int len = uiResults.SelectionLength;
  uiResults.Text += result + Environment.NewLine;
  uiResults.SelectionStart = pos;
  uiResults.SelectionLength = len;
  uiResults.ScrollToCaret();
}

添加线条时保持文本框滚动位置

自动滚动文本框使用的内存比预期多

问题中的代码完全实现了您要查找的内容。 添加了文本,但仅当滚动条位于最底部时才会滚动。

我遇到了同样的问题。最后,我做了一个简单的方法。(对不起,我不擅长英语。

关键点是使用 GetCharIndexFromPosition 方法获取第一个显示的字符索引。

//Get current infomation
int selStart = textBox.SelectionStart;
int selLen = textBox.SelectionLength;
int firstDispIndex = textBox.GetCharIndexFromPosition(new Point(3, 3));
//Append Text
textBox.AppendText(...);
//Scroll to original displayed position
textBox.Select(firstDispIndex, 0);
text.ScrolltoCaret();
//Restore original Selection
textBox.Select(selStart, selLen);

而且,如果文本框正在闪烁,请使用此扩展名。在添加文本之前调用 textBox.Suspend(),在添加文本后调用 textBox.Resume()。

namespace System.Windows.Forms
{
    public static class ControlExtensions
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern bool LockWindowUpdate(IntPtr hWndLock);
        public static void Suspend(this Control control)
        {
            LockWindowUpdate(control.Handle);
        }
        public static void Resume(this Control control)
        {
            LockWindowUpdate(IntPtr.Zero);
        }
    }
}

希望这对您有所帮助。谢谢~

您是否愿意接受另一种方法,因为您肯定会以这种方式陷入麻烦,并且解决方案将变得复杂(您想要避免的 pinvoke 等)。例如。假设您找到了一种方法来"检测用户是否已向后滚动",并且您停止滚动到底部。但是在阅读该行后,用户可能希望恢复滚动到底部的功能。那么为什么不为用户提供一种控制自动滚动的方法。这是我会怎么做的...

使用 RichTextBox 显示数据,使用复选框控制自动滚动,则代码可能如下所示:

        richTextBox1.AppendText(result + Environment.NewLine);
        if (checkBoxAutoScroll.Checked)
        {
            richTextBox1.SelectionStart = richTextBox1.Text.Length;
            richTextBox1.ScrollToCaret(); 
        }

默认情况下,富文本框不会自动滚动到 AppendText 的底部,因此第一行将始终可见(而不是新附加的行)。但是,如果用户选中此名为AutoScroll的复选框,我们的代码会将富文本框滚动到显示新行的底部。如果用户想要手动滚动以阅读一行,他首先需要取消选中该复选框。