making a .NET TextBox work FIFO style

末鹿安然 提交于 2019-12-12 14:10:02

问题


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.


回答1:


To create a circular buffer for text, I'd use a StringBuilder, with the capacity set to about twice the amount of data I want to display.

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

The fast path, when none of the if conditions are true, avoids all unnecessary copies (in the .NET world where strings are immutable, the final copy to create the output string cannot be avoided). And in the other cases only needed characters are copied. Increasing the capacity of the buffer will improve utilization fraction of the fast path. What I've been careful to avoid doing is creating a string object with the old content that remains on the display, which has no purpose except to concatenate with the new content, and immediately becomes garbage.

Obviously, if you use p/invoke to pass a pointer to the StringBuffer's content instead of copying out a substring, that will be even more efficient.




回答2:


While I'm sure there is a better solution - when I think FIFO - I think Queue. So, you could do something like make a Queue of strings to add your log items to and set up an integer to represent max number of log items.

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

then you could set up a logging method like so.

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

This should get you the functionality that you are looking for.

The one obvious drawback with this approach - is that you have your text stored in memory twice. Once in the queue and once as a concatenated string in the text box. If this isn't a big issue for you - then this may work.




回答3:


You could try something like this.

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

This is a very simple solution, so you'd need to do some extra work to get it to check for new lines and other such conditions, but it's where I would start.




回答4:


You can use the ListBox control and add new items to the beginning of the list, like this:

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

Then you can remove the oldest from the list box, like this:

ListBox1.Items.RemoveAt(ListBox1.Items.Count - 1);



回答5:


It kind of depends on your needs and the look you are after.

The approach I took was to creat A Scrolling Status Control that automatically tracks the last n lines of output, scrolls as needed, and renders the output correctly.

I was kind of going for the scrolling text window at the bottom of Visual Studio such as during compilation, but I ended up with something far less functional. But it is extremely light on resources. You might take a look and see if something similar would work for you.




回答6:


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


来源:https://stackoverflow.com/questions/18988170/making-a-net-textbox-work-fifo-style

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!