head.WriteLine()

Donnerstag, Oktober 26, 2006

ConsoleTraceListener in WinForms nutzen, Teil 3

Wie im ersten und zweiten Teil bereits gezeigt, ist die Anzeige eines Konsolenfensters eine recht praktische Sache. Doch es geht noch schöner: Wenn Sie in Ihrer Anwendung mit Docking Windows arbeiten oder ein spezielles Trace-Panel in Ihrem Hauptfenster haben, können Sie den Trace-Output der Konsole auf dieses umleiten. Und das Beste: Sie kommen hierbei sogar völlig ohne Windows-API-Deklarationen aus!

Für die Umleitung der Anwendungskonsole bietet die Console-Klasse die Methode SetOut(). Diese nimmt eine Instanz von System.IO.TextWriter entgegen und leitet in diese fortan die Ausgaben weiter. Somit könnten Sie den Output sehr leicht in eine Textdatei umleiten, doch dann hätten Sie kein Echtzeit-Tracing in der UI.

Daher müssen Sie eine Ableitung von TextWriter erstellen und die Daten beispielsweise an eine Textbox übergeben. Der Einfachheit halber habe ich mir dafür eine spezielle TextBox-Ableitung namens StandardOutputTextBox erstellt:

using System;
using System.ComponentModel;
using System.Windows.Forms;

[System.ComponentModel.DesignerCategory("Code")]
public class StandardOutputTextBox : TextBox
{
    private TextBoxWriter m_writer = null;

    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public TextBoxWriter Writer
    {
        get
        {
            if (m_writer != null)
            {
                return m_writer;
            }
            return new TextBoxWriter(this);
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing && (m_writer != null))
        {
            m_writer.Dispose();
        }
        base.Dispose(disposing);
    }
}

Dies bekommt eine Instanz von TextBoxWriter übergeben, meiner TextWriter-Ableitung. Dieser wird wiederum eine Instanz der StandardOutputTextBox übergeben, in die getraced werden soll.

TextBoxWriter sieht hierbei wie folgt aus:

using System;

public class TextBoxWriter : System.IO.TextWriter
{
    private System.Windows.Forms.TextBox m_box = null;

    public TextBoxWriter(System.Windows.Forms.TextBox box)
    {
        m_box = box;
    }

    public System.Windows.Forms.TextBox TextBox
    {
        get { return m_box; }
        set { m_box = value; }
    }

    public override System.Text.Encoding Encoding { get { return System.Text.Encoding.ASCII; } }
    public override void Write(bool value) { this.Write(value.ToString()); }
    public override void Write(char value) { this.Write(value.ToString()); }
    public override void Write(char[] buffer) { this.Write(new string(buffer)); }
    public override void Write(char[] buffer, int index, int count) { this.Write(new string(buffer, index, count)); }
    public override void Write(decimal value) { this.Write(value.ToString()); }
    public override void Write(double value) { this.Write(value.ToString()); }
    public override void Write(float value) { this.Write(value.ToString()); }
    public override void Write(int value) { this.Write(value.ToString()); }
    public override void Write(long value) { this.Write(value.ToString()); }
    public override void Write(string format, object arg0) { this.WriteLine(string.Format(format, arg0)); }
    public override void Write(string format, object arg0, object arg1) { this.WriteLine(string.Format(format, arg0, arg1)); }
    public override void Write(string format, object arg0, object arg1, object arg2) { this.WriteLine(string.Format(format, arg0, arg1, arg2)); }
    public override void Write(string format, params object[] arg) { this.WriteLine(string.Format(format, arg)); }
    public override void Write(uint value) { this.WriteLine(value.ToString()); }
    public override void Write(ulong value) { this.WriteLine(value.ToString()); }
    public override void Write(object value) { this.WriteLine(value.ToString()); }
    public override void WriteLine() { this.WriteLine(Environment.NewLine); }
    public override void WriteLine(bool value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(char value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(char[] buffer) { this.WriteLine(new string(buffer)); }
    public override void WriteLine(char[] buffer, int index, int count) { this.WriteLine(new string(buffer, index, count)); }
    public override void WriteLine(decimal value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(double value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(float value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(int value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(long value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(string format, object arg0) { this.WriteLine(string.Format(format, arg0)); }
    public override void WriteLine(string format, object arg0, object arg1) { this.WriteLine(string.Format(format, arg0, arg1)); }
    public override void WriteLine(string format, object arg0, object arg1, object arg2) { this.WriteLine(string.Format(format,
arg0, arg1, arg2)); }
    public override void WriteLine(string format, params object[] arg) { this.WriteLine(string.Format(format, arg)); }
    public override void WriteLine(uint value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(ulong value) { this.WriteLine(value.ToString()); }
    public override void WriteLine(object value) { this.WriteLine(value.ToString()); }

    public override void Write(string value)
    {
        m_box.Text = m_box.Text + value;
    }

    public override void WriteLine(string value)
    {
        m_box.Text += value + Environment.NewLine;
        System.Windows.Forms.Application.DoEvents();
    }
}

Wie Sie sehen passiert hier nichts Spektakuläres, es wird einfach der hereinkommende Content in die Textbox geschrieben.

Nun können Sie die StandardOutputTextBox auf eine Form ziehen und den Konsolen-Output an deren Writer-Eigenschaft umleiten.

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();

        // Console umleiten
        Console.SetOut(this.consoleTextBox.Writer);

        // ConsoleTraceListener anmelden
        Trace.Listeners.Add(new ConsoleTraceListener());
    }

    private void traceButton_Click(object sender, EventArgs e)
    {
        Trace.WriteLine("Hello Console Trace!");
    }
}

Das Ergebnis sieht nun erwartungsgemäß so aus:

2 Comments:

  • Ich war gerade auf der Suche nach einer Variante, wie ich alle Trace-Ausgaben zusätzlich in einer TextBox als Log anzeigen kann. Die Lösung von Ihnen hat mir dabei sehr geholfen. Coole Sache!

    By Anonymous Anonym, at Dezember 04, 2006 4:12 PM  

  • hello, here is a little sourceforge project under LGPL which does exactly that, its even threadsafe:
    http://sourceforge.net/projects/consolewidget/

    By Anonymous Anonym, at Juli 02, 2010 6:34 PM  

Kommentar veröffentlichen

<< Home