From 8a4095dae1058057a09c970e5ef8241746146e84 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sun, 21 Sep 2025 22:06:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=AA=97=E5=8F=A3=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RichTextBoxRowColoringRule.cs | 101 ++--- NLog.Windows.Wpf/RichTextBoxTarget.cs | 387 ++++++++++-------- .../RichTextBoxWordColoringRule.cs | 136 ++---- SpineViewer/Views/MainWindow.xaml | 1 + SpineViewer/Views/MainWindow.xaml.cs | 5 +- 5 files changed, 278 insertions(+), 352 deletions(-) diff --git a/NLog.Windows.Wpf/RichTextBoxRowColoringRule.cs b/NLog.Windows.Wpf/RichTextBoxRowColoringRule.cs index 9999a41..5bbe8c5 100644 --- a/NLog.Windows.Wpf/RichTextBoxRowColoringRule.cs +++ b/NLog.Windows.Wpf/RichTextBoxRowColoringRule.cs @@ -1,92 +1,53 @@ -// -// Copyright (c) 2004-2011 Jaroslaw Kowalski -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the name of Jaroslaw Kowalski nor the names of its -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -// - +using NLog; using NLog.Conditions; using NLog.Config; -using NLog; -using System.ComponentModel; +using NLog.Layouts; using System.Windows; + namespace NLog.Windows.Wpf { [NLogConfigurationItem] public class RichTextBoxRowColoringRule { - static RichTextBoxRowColoringRule() - { - Default = new RichTextBoxRowColoringRule(); - } - - public RichTextBoxRowColoringRule() - : this(null, "Empty", "Empty", FontStyles.Normal, FontWeights.Normal) - { - } - - public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor, FontStyle fontStyle, FontWeight fontWeight) - { - Condition = condition; - FontColor = fontColor; - BackgroundColor = backColor; - Style = fontStyle; - Weight = fontWeight; - } - - public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor) - { - Condition = condition; - FontColor = fontColor; - BackgroundColor = backColor; - Style = FontStyles.Normal; - Weight = FontWeights.Normal; - } - public static RichTextBoxRowColoringRule Default { get; private set; } [RequiredParameter] public ConditionExpression Condition { get; set; } - [DefaultValue("Empty")] - public string FontColor { get; set; } + public Layout FontColor { get; set; } + public Layout BackgroundColor { get; set; } - [DefaultValue("Empty")] - public string BackgroundColor { get; set; } + public FontStyle FontStyle { get; set; } + public FontWeight FontWeight { get; set; } - public FontStyle Style { get; set; } + static RichTextBoxRowColoringRule() + { + RichTextBoxRowColoringRule.Default = new RichTextBoxRowColoringRule(); + } - public FontWeight Weight { get; set; } + public RichTextBoxRowColoringRule() : this(null, "Empty", "Empty", FontStyles.Normal, FontWeights.Normal) { } + + public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor) + { + this.Condition = (ConditionExpression)condition; + this.FontColor = Layout.FromString(fontColor); + this.BackgroundColor = Layout.FromString(backColor); + this.FontStyle = FontStyles.Normal; + this.FontWeight = FontWeights.Normal; + } + + public RichTextBoxRowColoringRule(string condition, string fontColor, string backColor, FontStyle fontStyle, FontWeight fontWeight) + { + this.Condition = (ConditionExpression)condition; + this.FontColor = Layout.FromString(fontColor); + this.BackgroundColor = Layout.FromString(backColor); + this.FontStyle = fontStyle; + this.FontWeight = fontWeight; + } public bool CheckCondition(LogEventInfo logEvent) { - return true.Equals(Condition.Evaluate(logEvent)); + return true.Equals(this.Condition.Evaluate(logEvent)); } } } diff --git a/NLog.Windows.Wpf/RichTextBoxTarget.cs b/NLog.Windows.Wpf/RichTextBoxTarget.cs index 04d905d..81e18c3 100644 --- a/NLog.Windows.Wpf/RichTextBoxTarget.cs +++ b/NLog.Windows.Wpf/RichTextBoxTarget.cs @@ -1,34 +1,27 @@ -using NLog.Config; -using NLog.Layouts; +using NLog; +using NLog.Common; +using NLog.Config; using NLog.Targets; -using NLog; using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Text.RegularExpressions; +using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; -using System.Windows; namespace NLog.Windows.Wpf { - // TODO: 完善日志实现 [Target("RichTextBox")] public sealed class RichTextBoxTarget : TargetWithLayout { - private int lineCount; - private int _width = 500; - private int _height = 500; - private static readonly TypeConverter colorConverter = new ColorConverter(); + public static ReadOnlyCollection DefaultRowColoringRules { get; } = CreateDefaultColoringRules(); - static RichTextBoxTarget() + private static ReadOnlyCollection CreateDefaultColoringRules() { - var rules = new List() + return new List() { new RichTextBoxRowColoringRule("level == LogLevel.Fatal", "White", "Red", FontStyles.Normal, FontWeights.Bold), new RichTextBoxRowColoringRule("level == LogLevel.Error", "Red", "Empty", FontStyles.Italic, FontWeights.Bold), @@ -36,221 +29,253 @@ namespace NLog.Windows.Wpf new RichTextBoxRowColoringRule("level == LogLevel.Info", "Black", "Empty"), new RichTextBoxRowColoringRule("level == LogLevel.Debug", "Gray", "Empty"), new RichTextBoxRowColoringRule("level == LogLevel.Trace", "DarkGray", "Empty", FontStyles.Italic, FontWeights.Normal), - }; - - DefaultRowColoringRules = rules.AsReadOnly(); + }.AsReadOnly(); } - public RichTextBoxTarget() - { - WordColoringRules = new List(); - RowColoringRules = new List(); - ToolWindow = true; - } - - private delegate void DelSendTheMessageToRichTextBox(string logMessage, RichTextBoxRowColoringRule rule); - - private delegate void FormCloseDelegate(); - - public static ReadOnlyCollection DefaultRowColoringRules { get; private set; } + public RichTextBoxTarget() { } public string ControlName { get; set; } - public string FormName { get; set; } + public string WindowName { get; set; } - [DefaultValue(false)] public bool UseDefaultRowColoringRules { get; set; } - [ArrayParameter(typeof(RichTextBoxRowColoringRule), "row-coloring")] - public IList RowColoringRules { get; private set; } - - [ArrayParameter(typeof(RichTextBoxWordColoringRule), "word-coloring")] - public IList WordColoringRules { get; private set; } - - [DefaultValue(true)] - public bool ToolWindow { get; set; } - - public bool ShowMinimized { get; set; } - - public int Width - { - get { return _width; } - set { _width = value; } - } - - public int Height - { - get { return _height; } - set { _height = value; } - } - public bool AutoScroll { get; set; } public int MaxLines { get; set; } - internal Window TargetForm { get; set; } + [ArrayParameter(typeof(RichTextBoxRowColoringRule), "row-coloring")] + public IList RowColoringRules { get; } = new List(); - internal RichTextBox TargetRichTextBox { get; set; } + [ArrayParameter(typeof(RichTextBoxWordColoringRule), "word-coloring")] + public IList WordColoringRules { get; } = new List(); - internal bool CreatedForm { get; set; } + [NLogConfigurationIgnoreProperty] + public Window TargetWindow { get; set; } + + [NLogConfigurationIgnoreProperty] + public RichTextBox TargetRichTextBox { get; set; } protected override void InitializeTarget() { - TargetRichTextBox = Application.Current.MainWindow.FindName(ControlName) as RichTextBox; + base.InitializeTarget(); + if (TargetRichTextBox != null) + return; - if (TargetRichTextBox != null) return; - //this.TargetForm = FormHelper.CreateForm(this.FormName, this.Width, this.Height, false, this.ShowMinimized, this.ToolWindow); - //this.CreatedForm = true; - - var openFormByName = Application.Current.Windows.Cast().FirstOrDefault(x => x.GetType().Name == FormName); - if (openFormByName != null) + if (WindowName == null) { - TargetForm = openFormByName; - if (string.IsNullOrEmpty(ControlName)) - { - // throw new NLogConfigurationException("Rich text box control name must be specified for " + GetType().Name + "."); - Trace.WriteLine("Rich text box control name must be specified for " + GetType().Name + "."); - } - - CreatedForm = false; - TargetRichTextBox = TargetForm.FindName(ControlName) as RichTextBox; - - if (TargetRichTextBox == null) - { - // throw new NLogConfigurationException("Rich text box control '" + ControlName + "' cannot be found on form '" + FormName + "'."); - Trace.WriteLine("Rich text box control '" + ControlName + "' cannot be found on form '" + FormName + "'."); - } + HandleError("WindowName should be specified for {0}.{1}", GetType().Name, Name); + return; } - if (TargetRichTextBox == null) + if (string.IsNullOrEmpty(ControlName)) { - TargetForm = new Window - { - Name = FormName, - Width = Width, - Height = Height, - WindowStyle = ToolWindow ? WindowStyle.ToolWindow : WindowStyle.None, - WindowState = ShowMinimized ? WindowState.Minimized : WindowState.Normal, - Title = "NLog Messages" - }; - TargetForm.Show(); - - TargetRichTextBox = new RichTextBox { Name = ControlName }; - var style = new Style(typeof(Paragraph)); - TargetRichTextBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; - style.Setters.Add(new Setter(Block.MarginProperty, new Thickness(0, 0, 0, 0))); - TargetRichTextBox.Resources.Add(typeof(Paragraph), style); - TargetForm.Content = TargetRichTextBox; - - CreatedForm = true; + HandleError("Rich text box control name must be specified for {0}.{1}", GetType().Name, Name); + return; } + + var targetWindow = Application.Current.Windows.OfType().FirstOrDefault(w => w.Name == WindowName); + if (targetWindow == null) + { + InternalLogger.Info("{0}: WindowName '{1}' not found", this, WindowName); + return; + } + + var targetControl = targetWindow.FindName(ControlName) as RichTextBox; + if (targetControl == null) + { + InternalLogger.Info("{0}: WIndowName '{1}' does not contain ControlName '{2}'", this, WindowName, ControlName); + return; + } + + AttachToControl(targetWindow, targetControl); + } + + private static void HandleError(string message, params object[] args) + { + if (LogManager.ThrowExceptions) + { + throw new NLogConfigurationException(string.Format(message, args)); + } + InternalLogger.Error(message, args); + } + + private void AttachToControl(Window window, RichTextBox textboxControl) + { + InternalLogger.Info("{0}: Attaching target to textbox {1}.{2}", this, window.Name, textboxControl.Name); + DetachFromControl(); + TargetWindow = window; + TargetRichTextBox = textboxControl; + } + + private void DetachFromControl() + { + TargetWindow = null; + TargetRichTextBox = null; } protected override void CloseTarget() { - if (CreatedForm) - { - try - { - TargetForm.Dispatcher.Invoke(() => - { - TargetForm.Close(); - TargetForm = null; - }); - } - catch - { - } - - - - } + DetachFromControl(); } protected override void Write(LogEventInfo logEvent) { - RichTextBoxRowColoringRule matchingRule = RowColoringRules.FirstOrDefault(rr => rr.CheckCondition(logEvent)); - - if (UseDefaultRowColoringRules && matchingRule == null) + RichTextBox textbox = TargetRichTextBox; + if (textbox == null || textbox.Dispatcher.HasShutdownStarted || textbox.Dispatcher.HasShutdownFinished) { - foreach (var rr in DefaultRowColoringRules.Where(rr => rr.CheckCondition(logEvent))) - { - matchingRule = rr; - break; - } + //no last logged textbox + InternalLogger.Trace("{0}: Attached Textbox is {1}, skipping logging", this, textbox == null ? "null" : "disposed"); + return; } - if (matchingRule == null) - { - matchingRule = RichTextBoxRowColoringRule.Default; - } - - var logMessage = Layout.Render(logEvent); - - if (Application.Current == null) return; + string logMessage = RenderLogEvent(Layout, logEvent); + RichTextBoxRowColoringRule matchingRule = FindMatchingRule(logEvent); + _ = DoSendMessageToTextbox(logMessage, matchingRule, logEvent); + } + private bool DoSendMessageToTextbox(string logMessage, RichTextBoxRowColoringRule rule, LogEventInfo logEvent) + { + RichTextBox textbox = TargetRichTextBox; try { - if (Application.Current.Dispatcher.CheckAccess() == false) + if (textbox != null && !textbox.Dispatcher.HasShutdownStarted && !textbox.Dispatcher.HasShutdownFinished) { - Application.Current.Dispatcher.Invoke(() => SendTheMessageToRichTextBox(logMessage, matchingRule)); - } - else - { - SendTheMessageToRichTextBox(logMessage, matchingRule); + if (!textbox.Dispatcher.CheckAccess()) + { + textbox.Dispatcher.BeginInvoke(() => SendTheMessageToRichTextBox(textbox, logMessage, rule, logEvent)); + } + else + { + SendTheMessageToRichTextBox(textbox, logMessage, rule, logEvent); + } + return true; } } catch (Exception ex) { - Debug.WriteLine(ex); - } + InternalLogger.Warn(ex, "{0}: Failed to append RichTextBox", this); - } - - - private static Color GetColorFromString(string color, Brush defaultColor) - { - - if (color == "Empty") - { - return defaultColor is SolidColorBrush solidBrush ? solidBrush.Color : Colors.White; - } - - return (Color)colorConverter.ConvertFromString(color); - } - - - private void SendTheMessageToRichTextBox(string logMessage, RichTextBoxRowColoringRule rule) - { - RichTextBox rtbx = TargetRichTextBox; - - var tr = new TextRange(rtbx.Document.ContentEnd, rtbx.Document.ContentEnd); - tr.Text = logMessage + "\n"; - tr.ApplyPropertyValue(TextElement.ForegroundProperty, - new SolidColorBrush(GetColorFromString(rule.FontColor, (Brush)tr.GetPropertyValue(TextElement.ForegroundProperty))) - ); - tr.ApplyPropertyValue(TextElement.BackgroundProperty, - new SolidColorBrush(GetColorFromString(rule.BackgroundColor, (Brush)tr.GetPropertyValue(TextElement.BackgroundProperty))) - ); - tr.ApplyPropertyValue(TextElement.FontStyleProperty, rule.Style); - tr.ApplyPropertyValue(TextElement.FontWeightProperty, rule.Weight); - - - if (MaxLines > 0) - { - lineCount++; - if (lineCount > MaxLines) + if (LogManager.ThrowExceptions) { - tr = new TextRange(rtbx.Document.ContentStart, rtbx.Document.ContentEnd); - tr.Text.Remove(0, tr.Text.IndexOf('\n')); - lineCount--; + throw; + } + } + return false; + } + + private RichTextBoxRowColoringRule FindMatchingRule(LogEventInfo logEvent) + { + //custom rules first + if (RowColoringRules.Count > 0) + { + foreach (RichTextBoxRowColoringRule coloringRule in RowColoringRules) + { + if (coloringRule.CheckCondition(logEvent)) + { + return coloringRule; + } } } + if (UseDefaultRowColoringRules && DefaultRowColoringRules != null) + { + foreach (RichTextBoxRowColoringRule coloringRule in DefaultRowColoringRules) + { + if (coloringRule.CheckCondition(logEvent)) + { + return coloringRule; + } + } + } + + return RichTextBoxRowColoringRule.Default; + } + + private void SendTheMessageToRichTextBox(RichTextBox textBox, string logMessage, RichTextBoxRowColoringRule rule, LogEventInfo logEvent) + { + if (textBox == null) return; + + var document = textBox.Document; + + // 插入文本(带换行) + var tr = new TextRange(document.ContentEnd, document.ContentEnd) + { + Text = logMessage + Environment.NewLine + }; + + // 设置行级样式 + var fgColor = rule.FontColor?.Render(logEvent); + var bgColor = rule.BackgroundColor?.Render(logEvent); + + tr.ApplyPropertyValue(TextElement.ForegroundProperty, + string.IsNullOrEmpty(fgColor) || fgColor == "Empty" + ? textBox.Foreground + : new SolidColorBrush((Color)ColorConverter.ConvertFromString(fgColor))); + + tr.ApplyPropertyValue(TextElement.BackgroundProperty, + string.IsNullOrEmpty(bgColor) || bgColor == "Empty" + ? Brushes.Transparent + : new SolidColorBrush((Color)ColorConverter.ConvertFromString(bgColor))); + + tr.ApplyPropertyValue(TextElement.FontStyleProperty, rule.FontStyle); + tr.ApplyPropertyValue(TextElement.FontWeightProperty, rule.FontWeight); + + // Word coloring(在刚插入的范围内做匹配) + if (WordColoringRules.Count > 0) + { + foreach (var wordRule in WordColoringRules) + { + var pattern = wordRule.Regex?.Render(logEvent) ?? string.Empty; + var text = wordRule.Text?.Render(logEvent) ?? string.Empty; + var wholeWords = wordRule.WholeWords.RenderValue(logEvent); + var ignoreCase = wordRule.IgnoreCase.RenderValue(logEvent); + + var regex = wordRule.ResolveRegEx(pattern, text, wholeWords, ignoreCase); + var matches = regex.Matches(tr.Text); + + foreach (Match match in matches) + { + // 匹配到的部分范围 + var start = tr.Start.GetPositionAtOffset(match.Index, LogicalDirection.Forward); + var endPos = tr.Start.GetPositionAtOffset(match.Index + match.Length, LogicalDirection.Backward); + if (start == null || endPos == null) continue; + + var wordRange = new TextRange(start, endPos); + + var wordFg = wordRule.FontColor?.Render(logEvent); + var wordBg = wordRule.BackgroundColor?.Render(logEvent); + + wordRange.ApplyPropertyValue(TextElement.ForegroundProperty, + string.IsNullOrEmpty(wordFg) || wordFg == "Empty" + ? tr.GetPropertyValue(TextElement.ForegroundProperty) + : new SolidColorBrush((Color)ColorConverter.ConvertFromString(wordFg))); + + wordRange.ApplyPropertyValue(TextElement.BackgroundProperty, + string.IsNullOrEmpty(wordBg) || wordBg == "Empty" + ? tr.GetPropertyValue(TextElement.BackgroundProperty) + : new SolidColorBrush((Color)ColorConverter.ConvertFromString(wordBg))); + + wordRange.ApplyPropertyValue(TextElement.FontStyleProperty, wordRule.FontStyle); + wordRange.ApplyPropertyValue(TextElement.FontWeightProperty, wordRule.FontWeight); + } + } + } + + // 限制最大行数 + if (MaxLines > 0) + { + while (document.Blocks.Count > MaxLines) + { + document.Blocks.Remove(document.Blocks.FirstBlock); + } + } + + // 自动滚动到最后 if (AutoScroll) { - rtbx.ScrollToEnd(); + textBox.ScrollToEnd(); } } } -} +} \ No newline at end of file diff --git a/NLog.Windows.Wpf/RichTextBoxWordColoringRule.cs b/NLog.Windows.Wpf/RichTextBoxWordColoringRule.cs index b2e79c5..e577ad9 100644 --- a/NLog.Windows.Wpf/RichTextBoxWordColoringRule.cs +++ b/NLog.Windows.Wpf/RichTextBoxWordColoringRule.cs @@ -1,119 +1,59 @@ -// -// Copyright (c) 2004-2011 Jaroslaw Kowalski -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * Neither the name of Jaroslaw Kowalski nor the names of its -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -// - +using NLog.Config; +using NLog.Layouts; using System.ComponentModel; using System.Text.RegularExpressions; using System.Windows; -using NLog.Config; namespace NLog.Windows.Wpf { - [NLogConfigurationItem] + [NLogConfigurationItem] public class RichTextBoxWordColoringRule { - private Regex compiledRegex; + public Layout Regex { get; set; } + public Layout Text { get; set; } + public Layout WholeWords { get; set; } + public Layout IgnoreCase { get; set; } - public RichTextBoxWordColoringRule() + public Layout FontColor { get; set; } + public Layout BackgroundColor { get; set; } + + public FontStyle FontStyle { get; set; } + public FontWeight FontWeight { get; set; } + + internal Regex ResolveRegEx(string pattern, string text, bool wholeWords, bool ignoreCase) { - FontColor = "Empty"; - BackgroundColor = "Empty"; + if (string.IsNullOrEmpty(pattern) && text != null) + { + pattern = System.Text.RegularExpressions.Regex.Escape(text); + if (wholeWords) + pattern = "\b" + pattern + "\b"; + } + + RegexOptions options = RegexOptions.None; + if (ignoreCase) + options |= RegexOptions.IgnoreCase; + + return new Regex(pattern, options); // RegEx-Cache } + public RichTextBoxWordColoringRule() : this(null, "Empty", "Empty", FontStyles.Normal, FontWeights.Normal) { } + public RichTextBoxWordColoringRule(string text, string fontColor, string backgroundColor) { - Text = text; - FontColor = fontColor; - BackgroundColor = backgroundColor; - Style = FontStyles.Normal; - Weight = FontWeights.Normal; + this.Text = text; + this.FontColor = Layout.FromString(fontColor); + this.BackgroundColor = Layout.FromString(backgroundColor); + this.FontStyle = FontStyles.Normal; + this.FontWeight = FontWeights.Normal; } public RichTextBoxWordColoringRule(string text, string textColor, string backgroundColor, FontStyle fontStyle, FontWeight fontWeight) { - Text = text; - FontColor = textColor; - BackgroundColor = backgroundColor; - Style = fontStyle; - Weight = fontWeight; + this.Text = text; + this.FontColor = Layout.FromString(textColor); + this.BackgroundColor = Layout.FromString(backgroundColor); + this.FontStyle = fontStyle; + this.FontWeight = fontWeight; } - - public string Regex { get; set; } - - public string Text { get; set; } - - [DefaultValue(false)] - public bool WholeWords { get; set; } - - [DefaultValue(false)] - public bool IgnoreCase { get; set; } - - public FontStyle Style { get; set; } - - public FontWeight Weight { get; set; } - - public Regex CompiledRegex - { - get - { - if (compiledRegex == null) - { - string regexpression = Regex; - if (regexpression == null && Text != null) - { - regexpression = System.Text.RegularExpressions.Regex.Escape(Text); - if (WholeWords) - { - regexpression = "\b" + regexpression + "\b"; - } - } - - RegexOptions regexOptions = RegexOptions.Compiled; - if (IgnoreCase) - { - regexOptions |= RegexOptions.IgnoreCase; - } - - compiledRegex = new Regex(regexpression, regexOptions); - } - - return compiledRegex; - } - } - - [DefaultValue("Empty")] - public string FontColor { get; set; } - - [DefaultValue("Empty")] - public string BackgroundColor { get; set; } } } diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml index bda9156..0c5d959 100644 --- a/SpineViewer/Views/MainWindow.xaml +++ b/SpineViewer/Views/MainWindow.xaml @@ -9,6 +9,7 @@ xmlns:utils="clr-namespace:SpineViewer.Utils" xmlns:SFMLRenderer="clr-namespace:SFMLRenderer;assembly=SFMLRenderer" mc:Ignorable="d" + x:Name="_mainWindow" Title="{Binding Title}" Width="1500" Height="800" diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs index 3688730..d368096 100644 --- a/SpineViewer/Views/MainWindow.xaml.cs +++ b/SpineViewer/Views/MainWindow.xaml.cs @@ -111,14 +111,13 @@ public partial class MainWindow : Window var rtbTarget = new NLog.Windows.Wpf.RichTextBoxTarget { Name = "rtbTarget", - FormName = GetType().Name, + WindowName = _mainWindow.Name, ControlName = _loggerRichTextBox.Name, AutoScroll = true, MaxLines = 3000, - Layout = "[${level:format=OneLetter}]${date:format=yyyy-MM-dd HH\\:mm\\:ss} - ${message}" + Layout = "[${level:format=OneLetter}]${date:format=yyyy-MM-dd HH\\:mm\\:ss} - ${message}", }; - // TODO: 完善日志实现 rtbTarget.WordColoringRules.Add(new("[D]", "Gray", "Empty")); rtbTarget.WordColoringRules.Add(new("[I]", "DimGray", "Empty")); rtbTarget.WordColoringRules.Add(new("[W]", "DarkOrange", "Empty"));