C# 使.NET文本框以FIFO方式工作

C# 使.NET文本框以FIFO方式工作,c#,.net,user-interface,textbox,C#,.net,User Interface,Textbox,我有一个用C#编写的win GUI应用程序,其中有一个TextBox组件,我将日志写入其中。在某一点上,它加载得太多,整个应用程序开始动摇。 我想做一个有效的机制,使它成为先进先出,这意味着-使它成为一个固定的大小和删除最旧的内容自动 有没有任何.net/c功能可以实现这一点?否则,正确的方法是什么 更新:我对其他类型的文本数据也有这个问题,不仅仅是日志。因此,ListBox对我来说不是一个合适的解决方案。您可以使用ListBox控件向列表的开头添加新项目,如下所示: ListBox1.Item

我有一个用C#编写的win GUI应用程序,其中有一个
TextBox
组件,我将日志写入其中。在某一点上,它加载得太多,整个应用程序开始动摇。 我想做一个有效的机制,使它成为先进先出,这意味着-使它成为一个固定的大小和删除最旧的内容自动

有没有任何.net/c功能可以实现这一点?否则,正确的方法是什么


更新:我对其他类型的文本数据也有这个问题,不仅仅是日志。因此,
ListBox
对我来说不是一个合适的解决方案。

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

ListBox1.Items.Insert(0, "Newest Item");
ListBox1.Items.RemoveAt(ListBox1.Items.Count - 1);
然后可以从列表框中删除最旧的,如下所示:

ListBox1.Items.Insert(0, "Newest Item");
ListBox1.Items.RemoveAt(ListBox1.Items.Count - 1);

这在某种程度上取决于你的需要和你所追求的

我采用的方法是创建一个自动跟踪最后n行输出、根据需要滚动并正确呈现输出的程序


我有点倾向于在VisualStudio底部的滚动文本窗口,比如在编译过程中,但是我最终得到了一个功能性差得多的窗口。但它对资源的需求非常少。您可以看看类似的东西是否适合您。

要为文本创建循环缓冲区,我将使用
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);
}
const int DisplaySize=10000;
StringBuilder fifo=新的StringBuilder(2*DisplaySize);
字符串AppendToFifo(字符串s)
{
如果(s.Length>=DisplaySize){
//事实:显示将仅包括来自的数据
//因此,抛开整个缓冲区,只保留s的尾部
fifo.Clear();
fifo.追加(s,s.长度-显示大小,显示大小);
返回fifo.ToString();
}
if(先进先出长度+秒长>先进先出容量){
//事实:我们将使fifo溢出
//因此,仅在fifo中保留显示的数据
先进先出删除(0,先进先出长度+秒长度-显示大小);
}
先进先出。追加;

如果(fifo.Length你可以试试这样的东西

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

这是一个非常简单的解决方案,所以您需要做一些额外的工作来让它检查新行和其他类似的条件,但这就是我要开始的地方。

虽然我确信有更好的解决方案-当我想到FIFO时-我想到队列。所以,您可以做一些事情,比如创建一个字符串队列,将日志项添加到其中并设置一个整数表示日志项目的最大数量

private Queue<string> logQueue = new Queue<string>();
private const int logMax = 100;
这将为您提供所需的功能

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

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

使用列表框并删除项目。我的内容是自由文本,而不是面向行的,因此不会到期。我怀疑是否有任何内置内容。我的方法是使用某种类型的或MVVM,并维护一个具有以下内容的模型:1.以FIFO方式运行的日志项集合;2.一个名为
LogText
的计算属性,用于连接将这些行(或字符串)组合在一起。您可以将文本框绑定到此计算属性,并且每当添加日志条目时,您都会发出计算属性的更改通知,文本框应该自动更新。(这应该和它一样高效——对于在文本框中呈现,您必须在某个时候创建一个uberstring。要摆脱这一步骤,您必须以其他方式显示数据。)这是
winforms
还是
WPF
?SBs的设计目的是高效地追加;当您开始从字符串中间删除或将信息追加到字符串中间时,它们的效率并不特别高。@Servy:I从未插入(您错误地称之为“追加到中间”)或“从中间删除”。我确实从一开始就删除,但很少。即使这样也很便宜,因为我只做了一次删除操作,删除了一半以上的缓冲区——只需要复制保留的内容。选择。我只是想知道,与caackley建议的简单解决方案相比,在效率/资源消耗方面,有什么差距。@EdgarJamesluffternstat:我预计这将为GC创建大约一半的垃圾字符串来清理,因为他的创建了两个垃圾字符串,并将其中一个传递给
Text
属性,而我的创建了一个(您将传递给
Text
属性)。我认为做得更好需要p/invoke(我相信p/invoke to
SetWindowText
将剪切另一个副本以及剩余的垃圾字符串对象)。这应该行得通,但它会在每次调用时创建一个大小为
MaxLength+newText.Length
的垃圾字符串。这是我的回答小心避免的。@BenVoigt啊,很高兴知道。我对c#还是新手,所以像这样的小花絮非常有用。当然,我的要比这个复杂得多,所以可能应该用
Strin来包装它gTail
类或类似的东西,以隐藏调用代码的复杂性。