title: Elegant Log Window in WinForms C#
body: <p><strong>I am looking for ideas on an efficient way to implement a log window for a windows forms application. In the past I have implemented several using TextBox and RichTextBox but I am still not totally satisfied with the functionality.</strong></p>
  
  <p>This log is intended to provide the user with a recent history of various events, primarily used in data-gathering applications where one might be curious how a particular transaction completed. In this case, the log need not be permanent nor saved to a file.</p>
  
  <p>First, some proposed requirements:</p>
  
  <ul>
  <li>Efficient and fast; if hundreds of lines are written to the log in quick succession, it needs to consume minimal resources and time.</li>
  <li>Be able to offer a variable scrollback of up to 2000 lines or so. Anything longer is unnecessary.</li>
  <li>Highlighting and color are preferred. Font effects not required.</li>
  <li>Automatically trim lines as the scrollback limit is reached.</li>
  <li>Automatically scroll as new data is added.</li>
  <li>Bonus but not required: Pause auto-scrolling during manual interaction such as if the user is browsing the history.</li>
  </ul>
  
  <p>What I have been using so far to write and trim the log:</p>
  
  <p>I use the following code (which I call from other threads):</p>
  
  <pre><code>// rtbLog is a RichTextBox
  // _MaxLines is an int
  public void AppendLog(string s, Color c, bool bNewLine)
  {
      if (rtbLog.InvokeRequired)
      {
          object[] args = { s, c, bNewLine };
          rtbLog.Invoke(new AppendLogDel(AppendLog), args);
          return;
      }
      try
      {
          rtbLog.SelectionColor = c;
          rtbLog.AppendText(s);
          if (bNewLine) rtbLog.AppendText(Environment.NewLine);
          TrimLog();
          rtbLog.SelectionStart = rtbLog.TextLength;
          rtbLog.ScrollToCaret();
          rtbLog.Update();
      }
      catch (Exception exc)
      {
          // exception handling
      }
  }
  
  private void TrimLog()
  {
      try
      {
          // Extra lines as buffer to save time
          if (rtbLog.Lines.Length &lt; _MaxLines + 10)
          {
              return;
          }
          else
          {
              string[] sTemp = rtxtLog.Lines;
              string[] sNew= new string[_MaxLines];
              int iLineOffset = sTemp.Length - _MaxLines;
              for (int n = 0; n &lt; _MaxLines; n++)
              {
                  sNew[n] = sTemp[iLineOffset];
                  iLineOffset++;
              }
              rtbLog.Lines = sNew;
          }
      }
      catch (Exception exc)
      {
          // exception handling
      }
  }
  </code></pre>
  
  <p>The problem with this approach is that whenever TrimLog is called, I lose color formatting. With a regular TextBox this works just fine (with a bit of modification of course).</p>
  
  <p>Searches for a solution to this have never been really satisfactory. Some suggest to trim the excess by character count instead of line count in a RichTextBox. I've also seen ListBoxes used, but haven't successfully tried it.</p>