2010-12-13 3 views
1

J'ai un problème avec un log4netappender personnalisé, un agent de backgound et une zone de texte enrichi wpf. La zone de texte riche n'est pas mise à jour correctement lorsque je me connecte à partir d'un thread backgound.Problème d'appender personnalisé Log4net avec le répartiteur?

Lorsque j'appelle l'enregistreur du thread principal, le texte est correctement enregistré dans le composant d'interface utilisateur (la zone de texte enrichi). Mais quand j'appelle le logger d'un BackgroundWorker, l'événement de Logger Append est levé mais l'interface utilisateur (le richtextbox) n'est jamais mise à jour ... Pourquoi cela?

Merci pour toute aide!

Voici mon code d'une fenêtre principale contenant un bouton pour lancer BackgroundWorker et un contrôle personnalisé nammed « RichTraceBox »:

 private static readonly log4net.ILog _logger = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 

    TraceBox TheTraceBox; 

    public MainPanel() 
    { 
     InitializeComponent(); 

     // Configure Log4Net 
     Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository(); 
     hierarchy.Root.RemoveAllAppenders(); /*Remove any other appenders*/   
     //// .... create and configure appender .../// 
     WpfRichTextBoxAppender notify = new WpfRichTextBoxAppender(this.TheTraceBox); 
     PatternLayout layout = new PatternLayout(); 
     layout.ConversionPattern = "%d [%t] %-5p %c %m%n"; 
     notify.Layout = layout; 
     notify.ActivateOptions(); 


     log4net.Config.BasicConfigurator.Configure(notify); 
     _logger.Debug("Correctly logged"); 

     } 

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     BackgroundWorker checkGraphlongWorker = new BackgroundWorker(); 
     checkGraphlongWorker.DoWork += new DoWorkEventHandler(checkGraphlongWorker_DoWork); 
     checkGraphlongWorker.RunWorkerAsync(); 

    } 

    void checkGraphlongWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     Thread.Sleep(2000); 
     _logger.Debug("This is never Logged...."); 

     this.TheTraceBox.DisplayOnTraceBox("...But this is corectly displayed ???!!", Brushes.Red); 


     } 
...} 

Voici mon « WpfRichTextBoxAppender », un appender personnalisé pour log4net afficher des messages sur un contrôle personnalisé contenant un RichTextbox WPF:

/// <summary> 
/// Description of RichTextBoxAppender. 
/// </summary> 
public class WpfRichTextBoxAppender : AppenderSkeleton 
{ 
    #region Private Instance Fields 
    private TraceBox richTextBox = null; 
    private int maxTextLength = 100000; 
    #endregion 

    private delegate void UpdateControlDelegate(LoggingEvent loggingEvent); 

    #region Constructor 
    public WpfRichTextBoxAppender(TraceBox myRichTextBox) 
     : base() 
    { 
     richTextBox = myRichTextBox; 
    } 
    #endregion 


    protected override void Append(LoggingEvent[] loggingEvents) 
    { 
     base.Append(loggingEvents); 
    } 

    protected override void Append(LoggingEvent loggingEvent) 
    { 

     if (richTextBox != null) 
     { 
      // There may be performance issues if the buffer gets too long 
      // So periodically clear the buffer 
      if (richTextBox.TextLenght > maxTextLength) 
      { 
       richTextBox.ClearTrace(); 
      } 
      Brush color = Brushes.Black; 
      if (loggingEvent.Level == Level.Alert) 
       color = Brushes.Orange; 
      else if (loggingEvent.Level == Level.Critical) 
       color = Brushes.DarkOrange; 
      else if (loggingEvent.Level == Level.Error) 
       color = Brushes.Red; 
      else if (loggingEvent.Level == Level.Fatal) 
       color = Brushes.Red; 
      else if (loggingEvent.Level == Level.Warn) 
       color = Brushes.OrangeRed; 
      this.richTextBox.DisplayOnTraceBox(RenderLoggingEvent(loggingEvent), color); 
     } 
    } 
} 


public partial class TraceBox : UserControl 
{ 
    public TraceBox() 
    { 
     InitializeComponent(); 
     this.Visibility = System.Windows.Visibility.Visible; 
    }   

    private void Button_Clear_Click(object sender, RoutedEventArgs e) 
    { 
     this.ClearTrace(); 
     //this.Output.Text = ""; 
    } 


    public void ClearTrace() 
    { 
     FlowDocument myFlowDoc = new FlowDocument(); 
     this.ConsoleOutputTextBox.Document = myFlowDoc; 
    } 


    public int TextLenght { 
     get 
     { 
      TextRange tr = new TextRange(this.ConsoleOutputTextBox.Document.ContentStart, this.ConsoleOutputTextBox.Document.ContentEnd); 
      return tr.Text.Length; 
     } 
    } 

    private delegate void DisplayOnTraceBoxDel(object message, Brush messageColor); 
    public void DisplayOnTraceBox(object message, Brush messageColor) 
    {    
     if (!this.ConsoleOutputTextBox.Dispatcher.CheckAccess()) 
     { 
      this.ConsoleOutputTextBox.Dispatcher.Invoke(new DisplayOnTraceBoxDel(DisplayOnTraceBox), DispatcherPriority.DataBind, new object[] { message, messageColor }); 
     } 
     else 
     { 
      TextRange tr = new TextRange(this.ConsoleOutputTextBox.Document.ContentEnd, this.ConsoleOutputTextBox.Document.ContentEnd); 
      tr.Text = message.ToString(); 
      tr.ApplyPropertyValue(TextElement.FontFamilyProperty, "Consolas"); 
      tr.ApplyPropertyValue(TextElement.FontSizeProperty, 10D); 
      tr.ApplyPropertyValue(Paragraph.MarginProperty, new Thickness(0)); 
      //tr.ApplyPropertyValue(Paragraph.BackgroundProperty, "LightSteelBlue"); 
      tr.ApplyPropertyValue(TextElement.ForegroundProperty, messageColor); 
      this.ConsoleOutputTextBox.UpdateLayout(); 
     } 
    } 


} 

Répondre

0

Je n'ai pas utilisé WPF, donc je ne peux pas vraiment dire pourquoi, en particulier, cela ne fonctionne pas comme vous attendez. Cependant, j'ai trouvé ce link to a blog postingpeteohanlon montre comment faire un Appender log4net qui redirige sa sortie vers une zone de texte WPF. Il mentionne spécifiquement l'utilisation de INotifyPropertyChanged. Peut-être que quelque chose dans son message vous aidera.

De plus, voici un lien vers une autre réponse que je posté ici sur le SO qui relie plusieurs appenders à base TextBox (je ne pense pas que l'un d'eux sont WPF, malheureusement):

BackgroundWorker & Timer, reading only new lines of a log file?

0

J'ai eu le même problème et résolu avec un élément de paragraphe, comme tel ...

  _textBox.Dispatcher.BeginInvoke(new Action<string>(s => 
      {  
       Paragraph p = new Paragraph(); 
       p.Inlines.Add(new Run(s) { Foreground = Brushes.Red }); 
       ((RichTextBox)_textBox).Document.Blocks.Add(p); 
      }), msg); 
Questions connexes