views:

1012

answers:

3

For my WPF application I do logging to a text file using a TextWriterTraceListener. How can I also display the Trace output to a textbox?

A: 

you could append a custom Listener which updates the Textbox.Text property. You therefore need to inherit from the abstract base class TraceListener and override one of the TraaceData, TraceEvent, TraceTransfer methods.

Johannes Rudolph
+2  A: 

How about implementing a custom TraceListener that simply appends trace messages to a string? You then expose that string as a property, implement INotifyPropertyChanged and databind a TextBox control to that property.

Something like this:

public class MyTraceListener : TraceListener, INotifyPropertyChanged
{
    private readonly StringBuilder builder;

    public MyTraceListener()
    {
        this.builder = new StringBuilder();
    }

    public string Trace
    {
        get { return this.builder.ToString(); }
    }

    public override void Write(string message)
    {
        this.builder.Append(message);
        this.OnPropertyChanged(new PropertyChangedEventArgs("Trace"));
    }

    public override void WriteLine(string message)
    {
        this.builder.AppendLine(message);
        this.OnPropertyChanged(new PropertyChangedEventArgs("Trace"));
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}

You would need to add this TraceListener to the list of active listeners:

Trace.Listeners.Add(new MyTraceListener());
Mark Seemann
Thank you, it seems like a very good idea. I would appreciate some guidance.
iulianchira
Just remember that this approach isn't thread safe - don't hook it up to gui controls if you're logging from other threads than the gui thread
nos
@nos: Good point. I left that as an exercise to the reader :)
Mark Seemann
+3  A: 

I use this for C# winforms, should be easily adjustable to wpf

public class MyTraceListener : TraceListener
{
    private TextBoxBase output;

    public MyTraceListener(TextBoxBase output) {
        this.Name = "Trace";
        this.output = output;
    }


    public override void Write(string message) {

        Action append = delegate() {
            output.AppendText(string.Format("[{0}] ", DateTime.Now.ToString()));
            output.AppendText(message); 
        };
        if (output.InvokeRequired) {
            output.BeginInvoke(append);
        } else {
            append();
        }

    }

    public override void WriteLine(string message) {
        Write(message + Environment.NewLine);
    }
}

Use it like

TraceListener debugListener = new MyTraceListener (theTextBox);
Debug.Listeners.Add(debugListener);
Trace.Listeners.Add(debugListener);

Remember to Trace/Debug.Listeners.Remove(debugListener); when you don't need it anymore.

nos
+1 for BeginInvoke(). Regular Invoke() hangs entire app.
sharkin
You mean `new *My*TraceListener(theTextBox)`
Matthijs Wessels