3

I have a win GUI application written in C#, in which I have a TextBox component that I write my log to. at some point it gets too loaded and the entire app is starting to falter. I'd like to make an efficient mechanism to make it a FIFO, meaning - make it a fixed size and deleting the oldest content automatically.

is there any .net/c# feature for doing that? otherwise, what will be the right way to do this?

UPDATE: I also have this issue with other sort of textual data, and not only with logs. therefor, the ListBox is not a proper solution for me.

4

6 回答 6

6

虽然我确信有更好的解决方案 - 当我认为 FIFO 时 - 我认为是 Queue。因此,您可以执行一些操作,例如制作一个字符串队列来添加您的日志项,并设置一个整数来表示最大日志项数。

private Queue<string> logQueue = new Queue<string>();
private const int logMax = 100;

那么你可以像这样设置一个日志记录方法。

public void Log(string logText)
{
    // this should only ever run for 1 loop as you should never go over logMax
    // but if you accidentally manually added to the logQueue - then this would
    // re-adjust you back down to the desired number of log items.
    while (logQueue.Count > logMax - 1)
        logQueue.Dequeue();

    logQueue.Enqueue(logText);
    textBox.Text = string.Join(Environment.NewLine, logQueue.ToArray());
}

这应该可以为您提供您正在寻找的功能。

这种方法的一个明显缺点是您将文本存储在内存中两次。一次在队列中,一次作为文本框中的连接字符串。如果这对您来说不是一个大问题 - 那么这可能会奏效。

于 2013-09-24T18:08:47.403 回答
5

要为文本创建一个循环缓冲区,我会使用 a StringBuilder,其容量设置为我想要显示的数据量的两倍左右。

const int DisplaySize = 10000;
StringBuilder fifo = new StringBuilder(2 * DisplaySize);

string AppendToFifo( string s )
{
    if (s.Length >= DisplaySize) {
        // FACT: the display will only include data from s
        // therefore, toss the entire buffer, and only keep the tail of s
        fifo.Clear();
        fifo.Append(s, s.Length - DisplaySize, DisplaySize);
        return fifo.ToString();
    }
    if (fifo.Length + s.Length > fifo.Capacity) {
        // FACT: we will overflow the fifo
        // therefore, keep only data in the fifo that remains on the display
        fifo.Remove(0, fifo.Length + s.Length - DisplaySize);
    }
    fifo.Append(s);
    if (fifo.Length <= DisplaySize) {
        // FACT: the entire fifo content fits on the display
        // therefore, send it all
        return fifo.ToString();
    }
    // FACT: the fifo content exceed the display size
    // therefore, extract just the tail
    return fifo.ToString(fifo.Length - DisplaySize, DisplaySize);
}

当所有 if 条件都不为真时,快速路径会避免所有不必要的副本(在字符串不可变的 .NET 世界中,无法避免创建输出字符串的最终副本)。在其他情况下,只复制需要的字符。增加缓冲区的容量将提高快速路径的利用率。我一直小心避免做的是使用保留在显示器上的旧内容创建一个字符串对象,除了与新内容连接之外没有其他目的,并且立即变成垃圾。

显然,如果您使用 p/invoke 传递指向 StringBuffer 内容的指针而不是复制出子字符串,那将更加有效。

于 2013-09-24T17:50:46.413 回答
1

你可以试试这样的。

public void updateMyTextBox( string newText )
{
    // Get the current text, and append the newText to the end
    string text = MyTextBox.Text;
    text += newText;

    // Ensure text does not exceed maximum length
    if( text.Length > MaxLength ) // Max Length constant declared elsewhere
        text = text.Substring( text.Length - MaxLength );

    // Update MyTextBox
    myTextBox.Text = text;       
}

这是一个非常简单的解决方案,因此您需要做一些额外的工作来检查新行和其他此类情况,但这是我要开始的地方。

于 2013-09-24T17:53:27.887 回答
0

您可以使用ListBox控件并将新项目添加到列表的开头,如下所示:

ListBox1.Items.Insert(0, "Newest Item");

然后您可以从列表框中删除最旧的,如下所示:

ListBox1.Items.RemoveAt(ListBox1.Items.Count - 1);
于 2013-09-24T17:32:31.583 回答
0

这取决于您的需求和您所追求的外观。

我采用的方法是创建一个滚动状态控件,它会自动跟踪最后n行输出,根据需要滚动并正确呈现输出。

我有点想在 Visual Studio 底部滚动文本窗口,例如在编译期间,但我最终得到的东西功能少得多。但它对资源非常轻。你可以看看,看看类似的东西是否适合你。

于 2013-09-24T17:35:49.973 回答
-1

// LIFO 堆栈简单

    private void btnSend_Click(object sender, EventArgs e) // on button press
    {
        string oldText = rtbReceive.Text;          // copy old text from richTextBox
        rtbReceive.Clear();                        // Clear richTextBox

        rtbReceive.AppendText(tbSend.Text + "\r\n"); // add new text from textBox to richTextBox
        rtbReceive.AppendText(oldText);              // add old text to richTextBox

    // Best Regards by Petar Ivanov Upinov (BG)
    }
于 2015-03-19T13:11:02.347 回答