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.
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.
First, some proposed requirements:
- Efficient and fast; if hundreds of lines are written to the log in quick succession, it needs to consume minimal resources and time.
- Be able to offer a variable scrollback of up to 2000 lines or so. Anything longer is unnecessary.
- Highlighting and color are preferred. Font effects not required.
- Automatically trim lines as the scrollback limit is reached.
- Automatically scroll as new data is added.
- Bonus but not required: Pause auto-scrolling during manual interaction such as if the user is browsing the history.
What I have been using so far to write and trim the log:
I use the following code (which I call from other threads):
// 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 < _MaxLines + 10)
{
return;
}
else
{
string[] sTemp = rtxtLog.Lines;
string[] sNew= new string[_MaxLines];
int iLineOffset = sTemp.Length - _MaxLines;
for (int n = 0; n < _MaxLines; n++)
{
sNew[n] = sTemp[iLineOffset];
iLineOffset++;
}
rtbLog.Lines = sNew;
}
}
catch (Exception exc)
{
// exception handling
}
}
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).
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.