问题
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 aTextBox
.
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