<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [WPF] 在RichTextBox中輸出Microsoft.Extension.Logging庫的日志消息

      背景

      微軟的日志庫一般是輸出到控制臺的,但是在WPF中并不能直接使用控制臺,需要AllocConsole。
      但是這種做法個(gè)人覺得不太安全(一關(guān)閉控制臺整個(gè)程序就退出了?)。這時(shí)候就需要一個(gè)更加友好的方式輸出日志。

      問題

      那如何將日志的內(nèi)容顯示到RichTextBox中?

      實(shí)現(xiàn)LoggerProcessor

      • 這里參照官方的ConsoleLoggerProcessor,但是需要有點(diǎn)區(qū)別。
      public class RichTextBoxLoggerProcessor:IDisposable
      {
          ///...其他實(shí)現(xiàn)請參照Microsoft.Extension.Logging的源碼
          private readonly RichTextBoxDocumentStorage _storage;
          private readonly Thread _outputThread;
      
          /// 這個(gè)構(gòu)造函數(shù)傳入RichTextBoxDocumentStorage,用于顯示單條日志記錄
          public RichTextBoxLoggerProcessor(RichTextBoxDocumentStorage storage,       LoggerQueueFullMode fullMode, int maxQueueLength)
          {
              _storage = storage;
              _messageQueue = new();
              FullMode = fullMode;
              MaxQueueLength = maxQueueLength;
              _outputThread = new Thread(ProcessMessageQueue)
              {
                  IsBackground = true,
                  Name = "RichTextBox logger queue processing thread"
              };
              _outputThread.Start();
          }
      
          ///改寫WriteMessage方法,熟悉FlowDocument的兄弟應(yīng)該都知道Paragraph是什么吧
          public void WriteMessage(Paragraph message)
          {
              try
              {
                  //發(fā)送回FlowDocument所在的線程后添加Paragraph
                  _storage.Document?.Dispatcher.BeginInvoke(() =>
                  {
                      _storage.Document.Blocks.Add(message);
                  });
              }
              catch
              {
                  CompleteAdding();
              }
          }
      
          //同理改寫EnqueMessage方法和Enqueue等方法
          public void EnqueMessage(Paragraph message)
          {
              //...具體邏輯請參閱github源碼
          }
      
          public bool Enqueue(Paragraph message)
          {
              //...
          }
      
           public bool TryDequeue(out Paragraph entry)
           {
              //...
           }
      }
      
      public class RichTextBoxDocumentStorage
      {
          ///因?yàn)橐褂玫紻I,所以創(chuàng)建一個(gè)類來存放FlowDocument;
          public FlowDocument? Document{ get; set; }
      }
      

      實(shí)現(xiàn)RichTextBoxLogger

      • 這里繼承ILogger接口
      public class RichTextBoxLogger:ILogger
      {
          private string _category;
          private RichTextBoxLoggerProcessor _processor;
      
          public RichTextBoxLogger(string category, RichTextBoxLoggerProcessor processor, RichTextBoxFormatter formatter)
          {
              _category = category;
              _processor = processor;
              Formatter = formatter;
          }
      
          //LogEntry格式化器
          public RichTextBoxFormatter Formatter { get; set; }
      
          public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
          {
              var logEntry = new LogEntry<TState>(logLevel, _category, eventId, state, exception, formatter);
      
              //paragraph 需要在主線程創(chuàng)建
              App.Current.Dispatcher.BeginInvoke(() =>
              {
                  var message = Formatter.Write(in logEntry);
                  if (message is null)
                  {
                    return;
                  }
                  _processor.EnqueMessage(message);
            });
        }
      }
      
      public abstract class RichTextBoxFormatter
      {
          protected RichTextBoxFormatter(string name)
          {
              Name = name;
          }
      
          public string Name { get; }
      
          public abstract Paragraph? Write<TState>(in LogEntry<TState> logEntry);
      }
      

      創(chuàng)建LoggerProvider

      public class RichTextBoxLoggerProvider: ILoggerProvider
      {
          private readonly RichTextBoxFormatter _formatter;
          private readonly ConcurrentDictionary<string,RichTextBoxLogger> _loggers = [];
          private readonly RichTextBoxLoggerProcessor _processor;
          public RichTextBoxLoggerProvider(RichTextBoxDocumentStorage storage, RichTextBoxFormatter formatter)
          {
              _formatter = formatter;
              _processor = new RichTextBoxLoggerProcessor(storage, LoggerQueueFullMode.Wait, 2500);
              _formatter = formatter;
          }
      
          public ILogger CreateLogger(string categoryName)
          {
              return _loggers.GetOrAdd(categoryName, new RichTextBoxLogger(categoryName, _processor, _formatter));
          }
      }
      

      創(chuàng)建真正的LogViewer

      • 這里使用的是Window來展現(xiàn)日志
      public class LogViewer : Window
      {
          public LogViewer(RichTextBoxDocumentStorage storage)
          {
              InitializeComponent();
              if(storage.Document is null)
              {
                  //確保FlowDocument是在主線程上創(chuàng)建的
                  App.Current.Dispatcher.Invoke(()=>{
                      _storage.Document =  new FlowDocument() { TextAlignment = System.Windows.TextAlignment.Left }; 
                  });
              }
              logPresenter.Document = storage.Document;
          }
      }
      

      注冊服務(wù)

      public static class RichTextBoxLoggingExtension 
      {
          public static ILoggingBuilder AddRichTextBoxLogger(this ILoggingBuilder builder)
          {
              builder.Services.AddSingleton<RichTextBoxDocumentStorage>();
              //格式化的實(shí)現(xiàn)就不寫了,按自己的喜好來寫寫格式化器;這里是參照的SimpleConsoleFormatter實(shí)現(xiàn)的
              builder.Services.AddSingleton<RichTextBoxFormatter, SimpleRichTextBoxFormatter>();
              builder.Services.AddSingleton<ILoggerProvider,RichTextBoxLoggerProvider>();
              return builder;
          }
      }
      

      具體使用

      • 任意位置使用ServiceProvider喚起LogViewer即可
      public class SomeClass
      {
          public void OpenLogViewer()
          {
              App.Current.Services.GetRequiredService<LogViewer>().Show();
          }
      }
      

      結(jié)尾

      這里只是實(shí)現(xiàn)了個(gè)簡單的輸出,還有好多好多功能沒有實(shí)現(xiàn)。
      不喜歡寫太長的解釋說明,感覺好麻煩。代碼就是最好的說明(
      看哪天心血來潮了,做個(gè)nuget包吧。

      posted @ 2025-03-21 23:46  Echo_HR910  閱讀(582)  評論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 另类专区一区二区三区| 国产人妻精品午夜福利免费 | 成人性生交片无码免费看| 中文字幕亚洲人妻一区| 免费人成无码大片在线观看| 国产精品久久久久无码网站| 另类国产精品一区二区| 在国产线视频A在线视频| 亚洲成人av在线资源网| 天堂在线www天堂中文在线| 加勒比无码人妻东京热| 久久亚洲中文字幕伊人久久大| 国产精品亚洲二区在线播放| 欧美成人精品一级在线观看| 国产亚洲制服免视频| 欧美刺激性大交| 国内精品自线在拍| 长腿校花无力呻吟娇喘| 亚洲性美女一区二区三区| 中文无码av一区二区三区| 57pao成人国产永久免费视频| 99国产欧美另类久久久精品| 专栏| 丰满高跟丝袜老熟女久久| 国产午夜精品一区理论片| 日韩av日韩av在线| 国内自拍视频在线一区| 九九热精品在线观看| 蜜臀视频一区二区在线播放| 在线视频中文字幕二区| 精品人妻一区二区| 亚洲av无码成人精品区一区| 国产不卡一区二区精品| 国产成人精品一区二区不卡| 色综合久久蜜芽国产精品| 色综合热无码热国产| 四虎网址| 国产无遮挡免费视频免费| 无码人妻精品一区二| 精品婷婷色一区二区三区| 欧美福利电影A在线播放|