How can I use a RichTextBox as a NLog Target in a WPF application?

无人久伴 提交于 2019-11-30 04:47:58

问题


I read the following posts but neither helped to just get the same efficient way of printing logs from NLog onto a RichTextBox control target as in Winforms.

How can I use NLog's RichTextBox Target in WPF application?

WPF: Binding RichTextBox to Logger Output

I also browsed the official forum but with no success (except suggestions to read the two above posts).

The idea would be to add the target as:

<target xsi:type="RichTextBox" name="console"
     layout="${longdate:useUTC=true}|${level:uppercase=true}|${logger}::${message}"
     autoScroll="true"
     maxLines="1000000"
     controlName="rtbConsole"
     formName="MyWPFWindowName"
     useDefaultRowColoringRules="true">
</target>

And within the WPF window with MyWPFWindowName as name, to add a RichTextBox control with rtbConsole. Even if I create the target programmatically after the winow has been loaded, it will not use the existing rtbConsole but create a new form.

So, your help is appreciated!


回答1:


I created a custom NLog target and linked it to a text box.

public class NlogMemoryTarget : Target
{
    public Action<string> Log = delegate { };

    public NlogMemoryTarget (string name, LogLevel level)
    {
        LogManager.Configuration.AddTarget (name, this);

        LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", level, this));//This will ensure that exsiting rules are not overwritten
        LogManager.Configuration.Reload(); //This is important statement to reload all applied settings

        //SimpleConfigurator.ConfigureForTargetLogging (this, level); //use this if you are intending to use only NlogMemoryTarget  rule
    }

    protected override void Write (AsyncLogEventInfo[] logEvents)
    {
        foreach (var logEvent in logEvents) {
            Write (logEvent);
        }
    }

    protected override void Write (AsyncLogEventInfo logEvent)
    {
        Write (logEvent.LogEvent);
    }

    protected override void Write (LogEventInfo logEvent)
    {
        Log (logEvent.FormattedMessage);
    }
}


public partial class MainWindow
{
    private NlogMemoryTarget _Target;

    public MainWindow ()
    {
        InitializeComponent ();

        this.Loaded += (s, e) => {
            _Target = new NlogMemoryTarget ("text box output", LogLevel.Trace);
            _Target.Log += log => LogText (log);
        };
    }

    private void LogText (string message)
    {
        this.Dispatcher.Invoke ((Action) delegate () {
            this.MessageView.AppendText (message + "\n");
            this.MessageView.ScrollToEnd ();
        });
    }
}



回答2:


While this not really answer your question, but i believe this solution is better. An wpf control used to show NLog logs in listview. https://github.com/erizet/NlogViewer.




回答3:


As @mafu's answer suggests:

[Create] a custom NLog [memory] Target and [link] it to a TextBox.

This sample will 'link it' via event and Event Handler delegates.

Define a NLog Memory Target as a Type

public class NlogMemoryTarget : Target
{
    public event EventHandler<string> OnLog;

    public NlogMemoryTarget(string name, LogLevel level) : this(name, level, level) {}
    public NlogMemoryTarget(string name, LogLevel minLevel, LogLevel maxLevel)
    {
        // important: we want LogManager.Configuration property assign behaviors \ magic to occur
        //   see: https://stackoverflow.com/a/3603571/1366179
        var config = LogManager.Configuration;

        // Add Target and Rule to their respective collections
        config.AddTarget(name, this);
        config.LoggingRules.Add(new LoggingRule("*", minLevel, maxLevel, this));

        LogManager.Configuration = config;
    }

    [Obsolete]
    protected override void Write(AsyncLogEventInfo[] logEvents)
    {
        foreach (var logEvent in logEvents) {
            Write(logEvent.LogEvent);
        }
    }

    protected override void Write(AsyncLogEventInfo logEvent)
    {
        Write(logEvent.LogEvent);
    }

    protected override void Write(LogEventInfo logEvent)
    {
        OnLog(this, logEvent.FormattedMessage);
    }

    // consider overriding WriteAsyncThreadSafe methods as well.
}

Usage in WPF Window Control

public partial class MainWindow
{
    private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

    private NlogMemoryTarget _nlogMemoryTarget;

    public MainWindow()
    {
        InitializeComponent();

        _nlogMemoryTarget = new NlogMemoryTarget("TextBoxOutput", LogLevel.Trace);
        _nlogMemoryTarget.OnLog += LogText;
    }

    private void LogText(object sender, string message)
    {
        this.MessageView.AppendText($"{message}\n");
        this.MessageView.ScrollToEnd();
    }

    private void DoSomething() {
       logger.Trace("DoSomething called!");
    }
}

When you call on DoSomething (or do logger.Trace), your overloaded methods in your memory target will execute - which raises the event OnLog. Since you assigned an event handler, LogText, to OnLog in the construction of MainWindow, it will execute.




回答4:


I agree that the 2 referenced links in the question are not optimal. (I also would NOT use those solutions.)

Here's what I'd try:

Write a custom (WPF) control target using an algorithm similar to NLog's FormControlTarget.

Ensure to register your new target.
Also, NLog's FormHelper may be helpful.

Most of the WinForms code should be easily convertible to WPF.



来源:https://stackoverflow.com/questions/6617689/how-can-i-use-a-richtextbox-as-a-nlog-target-in-a-wpf-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!