8

在我的 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();
}
4

3 回答 3

4

自动滚动文本框使用的内存超出预期

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

于 2012-04-16T16:13:07.040 回答
1

我曾经也有过一样的问题。最后,我做了一个简单的方法。(对不起,我英语不好。)

关键是使用 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);
        }

    }
}

希望这会帮助你。谢谢~

于 2019-04-09T01:35:22.960 回答
0

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

使用 RichTextBox 显示数据并使用 Checkbox 来控制 AutoScrolling,那么您的代码可能是这样的:

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

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

于 2012-04-17T08:09:30.457 回答