Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 更新期间停止文本框闪烁_C#_Winforms_Textbox_Flicker - Fatal编程技术网

C# 更新期间停止文本框闪烁

C# 更新期间停止文本框闪烁,c#,winforms,textbox,flicker,C#,Winforms,Textbox,Flicker,我的WinForms应用程序有一个文本框,我将它用作日志文件。我正在使用TextBox.AppendText(string)添加文本,而表单不会闪烁,但是当我尝试清除旧文本时(当控件的.text属性达到.MaxLength限制时),我会得到可怕的闪烁 我使用的代码如下所示: public static void AddTextToConsoleThreadSafe(TextBox textBox, string text) { if (textBox.InvokeRequired)

我的WinForms应用程序有一个文本框,我将它用作日志文件。我正在使用
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()方法

文本框控件是否是最适合控制台日志的控件

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


我刚才也看到了,建议使用列表框,但是我不知道这在我的情况下是否有效,因为(在大多数情况下)我一次只接收一个字符的列表框文本。

您在主窗口上设置了双缓冲吗

在InitializeComponent调用之后,构造函数中的这段代码将添加双缓冲,并可能减少闪烁

this.SetStyle(
ControlStyles.AllPaintingWimPaint|
ControlStyles.UserPaint|
ControlStyles.DoubleBuffer,true)

是否在所有更新操作中尝试了SuspendLayout()/ResumeLayout()

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


如果您试图实现某种日志文件查看器,则可以使用列表框。

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

这将需要:

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

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

我发现使用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文本框中的闪烁。

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

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

Mathij的答案是对我有用。我对其进行了轻微修改,以便可以与任何控件一起使用-控件扩展:

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


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

可能需要将“if”改为“while”-以防删除第一行文本不足以使新文本适合文本框。这篇文章对此有更多信息-事实上它有一个非常明确的解决方案,即双缓冲不适用于文本框,所以你应该手动执行…Vinko,请将以上评论作为答案发布,这样我就可以接受了。只需使用RichTextBox即可。它是无闪烁的。将DetectUrls和ShortcutsEnabled属性设置为FALSE,以便与文本框更兼容。我尝试了双缓冲和SuspendLayout()/ResumeLayout(),不幸的是,它们似乎没有任何区别。我已经更新了关于使用列表框的问题,我不确定它是否有效,因为我(通常)一次添加一个字符。您可以更新列表框中的最后一项以添加字符,如果行已满,您可以添加一个新的列表框项。您是否在SuspendLayout()/ResumeLayout()中包含所有操作,包括ScrollToCaret调用?是的,我将suspend/resume作为方法调用部分的第一个和最后一个语句。另外,再仔细想想,我认为listbox不起作用,因为用户需要能够将文本复制到剪贴板。他们需要能够使用单击/拖动来选择要复制的文本。这不仅仅会增加闪烁的速度吗?这给了我一个想法,在找到更好的解决方案之前,我可以使用它。当控件填充时,我现在清除大约20%的内容(我可以减少20%,尽管我希望它能正常工作)。这样,当控件已满时,您就不太可能注意到闪烁,因为闪烁可能仅每小时发生一次,而不是每秒几次。我必须承认,这些周期没有经过多少思考:)尽管我接受了这个问题,我找到的最好答案是Vinko在回答我最初的问题时的评论。请大家使用RichTextBox。它是无闪烁的。将DetectUrls和ShortcutsEnabled属性设置为FALSE,以便与文本框更兼容。它真的很好用,否则你需要覆盖文本框的绘画信息,自己控制剪辑/验证区域;文本框本身就是闪烁的,你最好希望减少它。谢谢,对我也适用-事实上,我使用了mkajFYI的扩展,如果
//在此处执行操作,
是一个调整大小的事件,则该扩展不起作用。
是一个调整大小的事件。“LockWindowUpdate不用于一般用途的窗口重绘抑制。请使用WM_SETREDRAW消息禁用特定窗口的重绘。”