3

I would like to use a RichTextBox WPF control to print log outputs, but I am wondering what is the most efficient way to remove the "oldest" lines after there are for example more than 10,000 lines displayed, if it is possible to actually implement a queue behaviour, especially as there is no easy "Text" property to play with.

Unfortunately, I am not able to achieve this result with nlog either probably due to a bug or a limitation.

Community
  • 1
  • 1
Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
  • 1
    The bug is probably in this line: tr.Text.Remove(0, tr.Text.IndexOf('\n')); This is very common bug. Result from Remove() method is lost because string.Replace doesn’t replace anything in the original string. – CoperNick Feb 27 '14 at 16:44

2 Answers2

5

You can use a Queue<string> to store your log messages, and display them using the RichTextBox.Lines property.

For example:

    private const int _maxCapacity = 10000;

    private Queue<string> _messageQueue = new Queue<string>(_maxCapacity);

    private void button1_Click(object sender, EventArgs e)
    {
        if (_messageQueue.Count >= _maxCapacity)
        {
            _messageQueue.Dequeue();
        }

        _messageQueue.Enqueue("message " + _count++.ToString());

        richTextBox1.Lines = _messageQueue.ToArray();
    }

If you want the most recent messages to appear on top, reverse the queue:

richTextBox1.Lines = _messageQueue.Reverse().ToArray();
Jeff Ogata
  • 56,645
  • 19
  • 114
  • 127
  • with .NET 4.0, given the nature of logging to a control and thread safety, you should probably use [ConcurrentQueue](https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1?view=netframework-4.8) – Brett Caswell Dec 08 '19 at 20:31
3

If you extend the original control with a LineCount int property, it is possible to use this (inspired by some code given here):

if (this.MaxLines > 0)
{
    this.lineCount++;
    if (this.lineCount > this.MaxLines)
    {
        tr = new TextRange(rtbx.Document.ContentStart, rtbx.Document.ContentEnd);
        tr.Text = tr.Text.Remove(0, tr.Text.IndexOf('\n'));
        this.lineCount--;
    }
}

//And for auto scrolling
if (this.AutoScroll)
{
    rtbx.ScrollToEnd();
}
Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
  • 1
    Result from Remove() should be saved to tr.Text . Should be: tr.Text = tr.Text.Remove(0, tr.Text.IndexOf('\n')); – CoperNick Feb 27 '14 at 16:27