2009-09-07 6 views

Antwort

18

Ich benutze dies für C# WinForms, sollte leicht verstellbar sein

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); 
    } 
} 

Verwenden sie es wie

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

Remember zu Trace/Debug.Listeners.Remove (debugListener); wenn du es nicht mehr brauchst.

+0

+1 für BeginInvoke(). Regular Invoke() hängt die gesamte App. – sharkin

+0

Sie meinen 'neu * Mein * TraceListener (theTextBox)' –

+0

was ist das 'wpf Äquivalent' –

0

können Sie einen benutzerdefinierten Listener anhängen, der die Textbox.Text-Eigenschaft aktualisiert. Sie müssen daher von der abstrakten Basisklasse TraceListener übernehmen und eine der Methoden TraaceData, TraceEvent, TraceTransfer überschreiben.

11

Wie wäre es, einen benutzerdefinierten TraceListener zu implementieren, der Trace-Nachrichten einfach an eine Zeichenfolge anhängt? Sie geben dann diese Zeichenfolge als eine Eigenschaft frei, implementieren INotifyPropertyChanged und binden ein TextBox-Steuerelement an diese Eigenschaft.

Etwas wie folgt aus:

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); 
     } 
    } 
} 

Sie müssten diese Tracelistener in die Liste der aktiven Zuhörer hinzuzufügen:

Trace.Listeners.Add(new MyTraceListener()); 
+0

Vielen Dank, es scheint wie eine sehr gute Idee. Ich würde eine Anleitung schätzen. – kjv

+1

Denken Sie daran, dass dieser Ansatz nicht threadsicher ist - verbinden Sie ihn nicht mit GUI-Steuerelementen, wenn Sie von anderen Threads als dem GUI-Thread protokollieren – nos

+0

@nos: Guter Punkt. Ich überlasse das als Übung für den Leser :) –

2

Der folgende Code ist C# 6.0-Stil von @Mark Seemanns Code.

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

    public MyTraceListener() 
    { 
     _builder = new StringBuilder(); 
    } 

    public string Trace => _builder.ToString(); 

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

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

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     PropertyChanged?.Invoke(this, e); 
    } 
} 

sei angenommen, dass MainViewModel Stammdatei DataContext von MainWindow.xaml ist. Um MyTraceListener in MVVM-Art anzuwenden, schreiben Sie den folgenden Code in MainViewModel.cs.

private string _traceOutput; 
private readonly MyTraceListener _trace = new MyTraceListener(); 

// Constructor 
public MainViewModel() { 

    // ...your viewmodel initialization code. 

    // Add event handler in order to expose logs to MainViewModel.TraceOutput property. 
    WeakEventManager<INotifyPropertyChanged, PropertyChangedEventArgs>.AddHandler(_trace, "PropertyChanged", traceOnPropertyChanged); 
    Trace.Listeners.Add(_trace); 
} 

private void traceOnPropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    if (e.PropertyName == "Trace") 
     TraceOutput = _trace.Trace; 
} 

public string TraceOutput 
{ 
    get { return _traceOutput; } 
    set { 
     _traceOutput = value; 
     RaisePropertyChanged(); // This method is from Mvvm-light. 
    } 
} 

In MainWindow.xaml binden TraceOutput Eigenschaft auf TextBox. Wenn Sie möchten, dass die TextBox zusammen mit angesammelten Protokollen nach unten blättert, wenden Sie das Ereignis TextChanged an.

<TextBox x:Name="TextBoxLog" TextWrapping="Wrap" Text="{Binding TraceOutput}" VerticalScrollBarVisibility="Auto" AcceptsReturn="True" TextChanged="TextBoxLog_OnTextChanged" /> 

in Code-Behind der XAML-Datei (MainWindow.xaml.cs), ist Event-Handler einfach wie unten.

private void TextBoxLog_OnTextChanged(object sender, TextChangedEventArgs e) 
    { 
     TextBoxLog.ScrollToEnd(); 
    } 
Verwandte Themen