Introduction
This is a simple custom TraceListener
class to allow text boxes to show the result of the trace in a multi-threaded application.
Background
I was writing a test harness for one of my services and figured someone would have already published a TextBoxTraceListener
class to save me five minutes, but unfortunately Google came up short. The only examples I could see weren't threadsafe and would have needed all the code to be executed on the Windows UI thread - not exactly great when you're running a service test harness. So I figured I'd throw one together and put it out there for re-use. It's a very simple class really just to save people a bit of time.
Using the Code
Just add the TextBoxTraceListener
class to your code, then create an instance of the listener (passing in the textbox you want to output the trace to in the constructor), then add your trace listener to Trace
or Debug
. The sample test harness should give you a pretty good idea of what to do, but it's probably going to look something like this (where txtDisplayTrace
is a text box on the form):
public partial class Form1 : Form
{
TextBoxTraceListener _textBoxListener;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_textBoxListener = new TextBoxTraceListener(txtDisplayTrace);
Trace.Listeners.Add(_textBoxListener);
}
}
Points of Interest
I very rarely get to do anything that requires a UI, so I frequently forget that you can't access controls from a different thread until I compile and get an error (then the memory of previous pains comes flooding back). Of course to solve this issue, all you have to do is call Invoke
on the control in question and pass it a delegate to the method you want to execute, which is pretty much all that the TextBoxTraceListener
does; extend the TraceListener
class and invoke the update method (the code file has comments, which I've stripped from here).
public class TextBoxTraceListener : TraceListener
{
private TextBox _target;
private StringSendDelegate _invokeWrite;
public TextBoxTraceListener(TextBox target)
{
_target = target;
_invokeWrite = new StringSendDelegate(SendString);
}
public override void Write(string message)
{
_target.Invoke(_invokeWrite, new object[] { message });
}
public override void WriteLine(string message)
{
_target.Invoke(_invokeWrite, new object[]
{ message + Environment.NewLine });
}
private delegate void StringSendDelegate(string message);
private void SendString(string message)
{
_target.Text += message;
}
}
Hopefully someone out there will find it useful for saving five minutes of coding.