我有一个用C#编写的win GUI应用程序,其中我有一个TextBox
组件,我将日志写入。在某些时候,它太过负载,整个应用程序开始动摇。
我想建立一个有效的机制,使其成为一个FIFO,意思是 - 使其固定大小并自动删除最旧的内容。
是否有任何.net / c#功能?否则,这样做的正确方法是什么?
更新:我还有其他类型的文本数据,而不仅仅是日志。因此,ListBox
对我来说不是一个合适的解决方案。
答案 0 :(得分: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());
}
这可以为您提供所需的功能。
这种方法的一个明显缺点是你将文本存储在内存中两次。一旦进入队列,一次作为文本框中的连接字符串。如果这对您来说不是一个大问题 - 那么这可能有用。
答案 1 :(得分:5)
要为文本创建循环缓冲区,我会使用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内容的指针而不是复制出一个子字符串,那就更有效了。
答案 2 :(得分: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;
}
这是一个非常简单的解决方案,因此您需要做一些额外的工作来检查新线路和其他此类条件,但这是我要开始的地方。
答案 3 :(得分:0)
您可以使用ListBox
控件并将新项目添加到列表的开头,如下所示:
ListBox1.Items.Insert(0, "Newest Item");
然后你可以从列表框中删除最旧的,如下所示:
ListBox1.Items.RemoveAt(ListBox1.Items.Count - 1);
答案 4 :(得分:0)
这取决于您的需求和您所追求的外观。
我采用的方法是创建A Scrolling Status Control,自动跟踪最后的 n 输出行,根据需要滚动,并正确呈现输出。
我有点想要在Visual Studio底部的滚动文本窗口,例如在编译期间,但我最终得到了一些功能更少的东西。但它对资源的影响非常小。你可以看一下,看看类似的东西是否适合你。
答案 5 :(得分:-1)
// LIFO Stack simple
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)
}