目录
一.使用RichTextBox输出实时信息到窗体
二.保存输出记录到电脑本地文件夹中
三.在Winform界面查询RichTextBox控件输出的文本内容
一.使用RichTextBox输出实时信息到窗体
不用重写RichTextBox控件,只需要继承自TextWriter类,它是一个抽象类。
这样做的主要目的是,当我们在程序的任何地方直接使用
Console.WriteLine();
Console.WriteLine()输出语句输出异常或者正常信息的时候,它都能够把实时信息显示在RichTextBox中
首先窗体托入一个 RichTextBox控件
其次新建一个TextBoxWriter类
public class TextBoxWriter : System.IO.TextWriter
{
RichTextBox rtBox;
delegate void VoidAction();
public TextBoxWriter(RichTextBox box)
{
Control.CheckForIllegalCrossThreadCalls = false;
rtBox = box;
}
public override void WriteLine(string value)
{
VoidAction action = delegate
{
try
{
//保存信息到文件夹
DbLogger.LogWrite(value);
string[] strLines = rtBox.Text.Split('n');
if (strLines.Length > 1000)
{
rtBox.Clear();
}
if (!string.IsNullOrEmpty(value))
{
//让文本框获取焦点
rtBox.Focus();
//设置光标的位置到文本尾
rtBox.Select(rtBox.TextLength, 0);
//滚动到控件光标处
rtBox.ScrollToCaret();
rtBox.AppendText(string.Format("rn[{0:HH:mm:ss}]{1}rn", DateTime.Now, value));
//更改颜色
rtBox.ForeColor = Color.FromArgb(51, 255, 102);
}
else
{
rtBox.AppendText("暂无日志");
}
}
catch (Exception ex)
{
DbLogger.LogException(ex,ex.Message);
}
};
if (rtBox.IsHandleCreated)
{
try
{
rtBox.BeginInvoke(action);
}
catch { }
}
}
public override Encoding Encoding
{
get { return System.Text.Encoding.UTF8; }
}
}
接下来是最重要的一步,需要在窗体初始化时候,初始化
Console.SetOut(new TextBoxWriter(richTextBox1));//传入richTextBox1控件
最后调用,打印输出实时信息到richTextBox1控件
Console.WriteLine("Hello World!");
是的,只要在程序任何地方直接使用 Console.WriteLine()就能输出信息到richTextBox控件上。
二.保存输出记录到文件夹中
第一步,新建一个类项目:
在ClassLibrary1类库项目中,新建几个类,分别是LogRule (日志频率),LogLevel (日记级别),Logger (日记写入),DbLogger (日记调用)
////// 日志频率 /// public enum LogRule { Day, Hour, Minute, No }
////// 日志级别 /// public enum LogLevel { ////// 程序运行记录,Debug模式 /// AppTrace, ////// 程序运行错误 /// AppException, ////// 一般运行信息,主要日志方式 /// AppInfo, ////// 运行警告,由开发人员记录 /// AppWarn, ////// 接口运行记录,Debug模式 /// ApiTrace, ////// 接口运行错误 /// ApiException, ////// 接口一般运行信息,主要日志方式 /// ApiInfo, ////// 接口运行警告,由开发人员记录 /// ApiWarn, ////// sql执行记录 /// SqlTrace, ////// 抽奖统计记录 /// LuckTrace }
////// 日志写入 /// public class Logger { ////// 日志队列 /// private static ConcurrentQueue> _logQueue; /// /// 日志文件夹 /// /// private string _logPath = ConfigurationManager.AppSettings["LogPath"].ToString(); private int _size; private Timer _watcher; #region Instance private static readonly object _lockObject = new object(); private static volatile Logger _instance = null; ////// 写日志,通过队列容量或定时触发写入操作 /// /// 记录数,默认为100 /// 毫秒数,默认60秒 public Logger(int size = 100, int milliseconds = 60000) { //如果目录不存在则创建 if (!Directory.Exists(this._logPath)) Directory.CreateDirectory(this._logPath); _logQueue = new ConcurrentQueue>(); _size = size; _watcher = new Timer(milliseconds); _watcher.Elapsed += (o, e) => { Submit(); }; _watcher.Start(); } public static Logger Instance() { if (_instance == null) { lock (_lockObject) { if (_instance == null) { #if DEBUG _instance = new Logger(100, 3000); #else _instance = new Logger(); #endif } } } return _instance; } #endregion #region 写日志 /// /// 写日志 是一个入队操作 /// /// public void Write(string s, string prefix, LogRule rule = LogRule.Day) { if (string.IsNullOrWhiteSpace(s)) return; DateTime dt = DateTime.Now; string val = string.Concat(dt, "rn", s); string key = string.Concat(prefix, GetKey(dt, rule)); Write(key, val); } public void Write(string key, string val) { _logQueue.Enqueue(new KeyValuePair(key, val)); if (_logQueue.Count() >= _size) Submit(); } /// /// 写日志 是一个入队操作 /// /// public void Write(string s, LogLevel level = LogLevel.AppInfo, LogRule rule = LogRule.Day, long ms = 0) { string prefix = level.ToString(); if (ms > 0) ms = ms / 10 * 10; if (ms > 0) prefix = string.Concat("_", prefix, ms, "_"); Write(s, prefix, rule); } #endregion #region 文本记录日志 ////// 写入文本记录 /// public void Submit() { //独占方式,因为文件只能由一个进程写入. StreamWriter writer = null; var dict = GetLogText(); string filename; FileInfo file; try { lock (_lockObject) { foreach (var kv in dict) { filename = string.Concat(kv.Key, ".txt"); file = new FileInfo(this._logPath + "/" + filename); //文件不存在就创建,true表示追加 writer = new StreamWriter(file.FullName, true, Encoding.UTF8); writer.WriteLine(kv.Value); writer.Close(); } } } finally { if (writer != null) writer.Close(); } } private string GetKey(DateTime dt, LogRule rule) { string key; switch (rule) { case LogRule.Minute: key = dt.ToString("yyyyMMddHHmm"); break; case LogRule.No: key = ""; break; case LogRule.Day: key = dt.ToString("yyyyMMdd"); break; case LogRule.Hour: default: key = dt.ToString("yyyyMMddHH"); break; } return key; } ////// 得到日志文本 一个出队操作 /// 将主键相同的数据拼接到一起,减少写入的io操作 /// ///private ConcurrentDictionary GetLogText() { ConcurrentDictionary dict = new ConcurrentDictionary (); string key, val; do { KeyValuePair kv; if (_logQueue.TryDequeue(out kv)) { key = kv.Key; val = string.Concat(kv.Value, "rn----------------------------------------rn"); dict.AddOrUpdate(key, val, (k, v) => string.Concat(v + "rn" + val)); } } while (_logQueue.Count > 0); return dict; } #endregion }
public static class DbLogger
{
public static void LogWrite(string context)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Concat(context));
Logger.Instance().Write(sb.ToString(), LogLevel.AppInfo);
}
public static void LogException(Exception ex, string lastCommand = null)
{
StringBuilder sb = new StringBuilder();
if (!string.IsNullOrWhiteSpace(lastCommand))
sb.AppendLine(string.Concat("LastCommand:", lastCommand));
if (ex.InnerException != null)
ex = ex.InnerException;
sb.AppendLine(string.Concat("异常信息: " + ex.Message));
sb.AppendLine(string.Concat("错误源:" + ex.Source));
sb.AppendLine(string.Concat("堆栈信息:rn" + ex.StackTrace));
Logger.Instance().Write(sb.ToString(), LogLevel.AppInfo);
}
}
重新编译解决方案,最后调用,在需要使用日记的项目里面引用ClassLibrary1类库
调用方式 1
DbLogger.LogWrite("Hello World!");
调用方式 2
try
{
//代码逻辑
}
catch (Exception ex)
{
DbLogger.LogException(ex, ex.Message);
}
小技巧:
ConfigurationManager配置说明请查看:https://blog.csdn.net/weixin_39237340/article/details/92561824
private string _logPath = ConfigurationManager.AppSettings["LogPath"].ToString();
以上内容出忘记出自那了,项目里面用到,就拿来记录分享一下。如有侵权请联系本人,删除。
三.界面RichTextBox控件查询输出的文本内容
RichTextBox控件查找文本演示,包括查找第一个/下一个/上一个/最后一个.
网上有很多方法,但是不能实现查询上一个功能。
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace vjsdn_tester
{
//操作RichTextBox控件的类. by www.csframework.com
public class RichTextBoxTool
{
///
/// 自己定义查找方法.参数content是要查询的内容.
/// type是查询条件.如:从文件头部向下查询,从文件尾部向上查询.
/// 如type= RichTextBoxFinds.None 表示从文件头部向下查询.
///
public static void FindText(RichTextBox rich, string content, RichTextBoxFinds options)
{
int startIndex;
int endIndex;
if ((options & RichTextBoxFinds.Reverse) == RichTextBoxFinds.Reverse)
{
startIndex = 0;
endIndex = rich.SelectionStart;
}
else
{
startIndex = rich.SelectionStart + rich.SelectionLength;
endIndex = rich.Text.Length;
}
int index = rich.Find(content, startIndex, endIndex, options);
if (index >= 0) //如果找到
ShowSelection(rich, index, content.Length);
else
MessageBox.Show("Not found!");
}
//查找第一个
public static void FindFirst(RichTextBox rich, string content)
{
int index = rich.Find(content, 0);
if (index >= 0) ShowSelection(rich, index, content.Length);
}
//查找最后一个
public static void FindLast(RichTextBox rich, string content)
{
int index = rich.Find(content, rich.Text.Length, RichTextBoxFinds.Reverse);
if (index >= 0) ShowSelection(rich, index, content.Length);
}
//选择搜索到的文本
private static void ShowSelection(RichTextBox rich, int index, int length)
{
rich.SelectionStart = index;
rich.SelectionLength = length;
rich.SelectionColor = Color.Red;
rich.Focus();
}
}
}
测试代码调用
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace vjsdn_tester
{
public partial class frmRichboxSearher : Form
{
public frmRichboxSearher()
{
InitializeComponent();
}
//查找下一个单词
private void btnFindNext_Click(object sender, EventArgs e)
{
string content = txtContent.Text;
RichTextBoxTool.FindText(this.richTextBox1, content, RichTextBoxFinds.None);
}
//查找第一个单词
private void btnFindFirst_Click(object sender, EventArgs e)
{
string content = txtContent.Text;
RichTextBoxTool.FindFirst(this.richTextBox1, content);
}
//查找上一个单词
private void btnFindPrior_Click(object sender, EventArgs e)
{
string content = txtContent.Text;
RichTextBoxTool.FindText(this.richTextBox1, content, RichTextBoxFinds.Reverse);
}
//查找最后一个单词
private void btnFindLast_Click(object sender, EventArgs e)
{
string content = txtContent.Text;
RichTextBoxTool.FindLast(this.richTextBox1, content);
}
}
}
出自:http://www.csframework.com/archive/2/arc-2-20110716-1729.htm



