14

我的 WinForms 应用程序有一个 TextBox,我将其用作日志文件。我正在附加文本而没有使用闪烁的表单TextBox.AppendText(string);,但是当我尝试清除旧文本时(因为控件的 .Text 属性达到 .MaxLength 限制),我得到了可怕的闪烁。

我正在使用的代码如下:

public static void AddTextToConsoleThreadSafe(TextBox textBox, string text)
{
    if (textBox.InvokeRequired)
    {
        textBox.Invoke(new AddTextToConsoleThreadSafeDelegate(AddTextToConsoleThreadSafe), new object[] { textBox, text });
    }
    else
    {
        // Ensure that text is purged from the top of the textbox
        // if the amount of text in the box is approaching the
        // MaxLength property of the control

        if (textBox.Text.Length + text.Length > textBox.MaxLength)
        {
            int cr = textBox.Text.IndexOf("\r\n");
            if (cr > 0)
            {
                textBox.Select(0, cr + 1);
                textBox.SelectedText = string.Empty;
            }
            else
            {
                textBox.Select(0, text.Length);
            }
        }


        // Append the new text, move the caret to the end of the
        // text, and ensure the textbox is scrolled to the bottom

        textBox.AppendText(text);
        textBox.SelectionStart = textBox.Text.Length;
        textBox.ScrollToCaret();
    }
}

有没有一种更简洁的方法可以从控件顶部清除不会导致闪烁的文本行?文本框没有 ListView 所具有的 BeginUpdate()/EndUpdate() 方法。

TextBox 控件甚至是最适合控制台日志的控件吗?

编辑: TextBox 闪烁似乎是文本框向上滚动到顶部(当我清除控件顶部的文本时),然后它立即向下滚动到底部。- 这一切都发生得很快,所以我只看到反复闪烁。

我也刚看到这个问题,建议使用 ListBox,但是我不知道这是否适用于我的情况,因为(在大多数情况下)我收到 ListBox 一个字符的文本一次。

4

6 回答 6

18

Mathijs 的答案对我有用。我已经稍微修改了它,所以我可以使用任何控件 - 控件扩展:

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

    }
}

所以你需要做的就是:

myTextBox.Suspend();
// do something here.
myTextBox.Resume();

效果很好。所有闪烁停止。

于 2013-07-28T22:23:32.987 回答
13

我在网上找到了一个解决方案:

    [System.Runtime.InteropServices.DllImport("user32.dll")]

    public static extern bool LockWindowUpdate(IntPtr hWndLock);

    internal void FillTB(TextBox tb, string mes) 
    {
       try
       {
          LockWindowUpdate(tb.Handle);

          // Do your thingies with TextBox tb
       }
       finally
       {
          LockWindowUpdate(IntPtr.Zero);
       }
    }
于 2012-02-02T14:55:25.153 回答
4

您是否在主窗口上设置了双缓冲?

InitializeComponent 调用后构造函数中的此代码将添加双缓冲并可能减少闪烁。

this.SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer,true);

于 2009-10-11T10:03:13.083 回答
3

我发现使用 SelectedText = text 会显着减少闪烁。对于非常快速的更新,闪烁将仅针对新文本进行本地化,您不会因滚动条的跳跃而出现任何奇怪的行为。

void UpdateTextBox(string message)
{
   myTextBox.SelectionStart = myTextBox.Text.Length;
   myTextBox.SelectedText = message;
}

您还可以使用它来覆盖以前编写的文本——因为您需要更新计数器或下载百分比,例如:

void UpdateTextBox(string message, int jumpBack)
{
   myTextBox.SelectionStart = Math.Max(myTextBox.Text.Length - jumpBack, 0);
   myTextBox.SelectionLength = jumpBack;
   myTextBox.SelectedText = message;
}

除此之外,似乎没有任何简单的方法可以减少 .NET TextBox 中的闪烁。

于 2011-11-02T17:52:20.473 回答
2

您是否围绕所有更新操作尝试了 SuspendLayout() / ResumeLayout()?

您也可以在文本框上调用 Clear(),然后重新分配截断的文本。

如果您尝试实现某种日志文件查看器,则可以改用 ListBox。

于 2009-10-11T10:07:23.427 回答
2

问题是您一次又一次地快速添加(删除)一个字符。一种解决方案是在添加字符时对其进行缓冲,并以更大的间隔(无论字符量如何)更新文本框,例如每 250 毫秒。

这将需要:

  • 在其中添加字符的数组或堆栈
  • 有一个计时器可以调用一个委托,该委托实际上会使用存储在堆栈中的字符进行更新

另一种选择是每 250 毫秒和 100 个字符都使用一次,无论先发生什么。但这可能会使代码更加复杂,而没有任何切实的好处。

于 2009-10-11T10:29:53.073 回答