Log4net 自定义附加程序与调度程序有问题吗?

发布于 2024-10-07 07:53:00 字数 5251 浏览 3 评论 0原文

我对自定义 log4netappender、后台工作人员和 wpf 富文本框有疑问。当我从后台线程登录时,富文本框未正确更新。

当我从主线程调用记录器时,文本会正确记录到 UI 组件(richtextbox)。但是,当我从 BackgroundWorker 调用记录器时,会引发记录器 Append 事件,但 UI(richtextbox)永远不会更新......为什么呢?

感谢您的帮助!

这是我的主窗口代码,其中包含启动后台工作程序的按钮和名为“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);


        }
...}

这是我的“WpfRichTextBoxAppender”,它是 log4net 的自定义附加程序,它在包含 wpf richTextBox 的自定义控件上显示消息:

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


}

I have a problem with a custom log4netappender, a backgound worker and a wpf rich text box. The rich text box is not updated correctly when I log from a backgound thread.

When I call the logger from the main thread, the text is correctly logged to the UI component (the richtextbox). But when I call the logger from a BackgroundWorker, the logger Append event is raised but the UI (the richtextbox) is never updated... Why that ?

Thanks for any help !

Here is my code of a main windows containing a button to launch backgroundworker and a custom control 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);


        }
...}

Here is my "WpfRichTextBoxAppender", a custom appender for log4net that display messages on a custom control containing a wpf richTextBox:

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


}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

昇り龍 2024-10-14 07:53:00

我没有使用过 WPF,所以我无法真正评论为什么它没有按照您的预期工作。但是,我确实找到了这个博客帖子链接 其中 peteohanlon 展示了如何制作将其输出重定向到 WPF 文本的 log4net Appender盒子。他特别提到了使用 INotifyPropertyChanged。也许他的帖子中的某些内容会对您有所帮助。

另外,这里是我在 SO 上发布的另一个答案的链接,它链接到几个基于 TextBox 的 Appender(不幸的是,我不认为它们都是 WPF):

BackgroundWorker &计时器,仅读取日志文件的新行?

I have not used WPF, so I can't really comment on why, specifically, this is not working as you expect it to. However, I did find this link to a blog posting where peteohanlon shows how to make a log4net Appender that redirects its output to a WPF text box. He specifically mentions using INotifyPropertyChanged. Maybe something in his post will help you.

Also, here is a link to another answer that I posted here on SO that links to several TextBox-based Appenders (I don't think any of them are WPF, unfortunately):

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

春风十里 2024-10-14 07:53:00

我遇到了同样的问题并用段落项目解决了它,所以......

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

I had the same problem and solved it with a Paragraph item, as so...

            _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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文