目录
一.使用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("\r\n[{0:HH:mm:ss}]{1}\r\n", 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 (日记调用)
/// <summary>
/// 日志频率
/// </summary>
public enum LogRule
{
Day,
Hour,
Minute,
No
}
/// <summary>
/// 日志级别
/// </summary>
public enum LogLevel
{
/// <summary>
/// 程序运行记录,Debug模式
/// </summary>
AppTrace,
/// <summary>
/// 程序运行错误
/// </summary>
AppException,
/// <summary>
/// 一般运行信息,主要日志方式
/// </summary>
AppInfo,
/// <summary>
/// 运行警告,由开发人员记录
/// </summary>
AppWarn,
/// <summary>
/// 接口运行记录,Debug模式
/// </summary>
ApiTrace,
/// <summary>
/// 接口运行错误
/// </summary>
ApiException,
/// <summary>
/// 接口一般运行信息,主要日志方式
/// </summary>
ApiInfo,
/// <summary>
/// 接口运行警告,由开发人员记录
/// </summary>
ApiWarn,
/// <summary>
/// sql执行记录
/// </summary>
SqlTrace,
/// <summary>
/// 抽奖统计记录
/// </summary>
LuckTrace
}
/// <summary>
/// 日志写入
/// </summary>
public class Logger
{
/// <summary>
/// 日志队列
/// </summary>
private static ConcurrentQueue<KeyValuePair<string, string>> _logQueue;
/// <summary>
/// 日志文件夹
/// </summary>
///
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;
/// <summary>
/// 写日志,通过队列容量或定时触发写入操作
/// </summary>
/// <param name="capacity">记录数,默认为100</param>
/// <param name="seconds">毫秒数,默认60秒</param>
public Logger(int size = 100, int milliseconds = 60000)
{
//如果目录不存在则创建
if (!Directory.Exists(this._logPath))
Directory.CreateDirectory(this._logPath);
_logQueue = new ConcurrentQueue<KeyValuePair<string, string>>();
_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 写日志
/// <summary>
/// 写日志 是一个入队操作
/// </summary>
/// <param name="str"></param>
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, "\r\n", s);
string key = string.Concat(prefix, GetKey(dt, rule));
Write(key, val);
}
public void Write(string key, string val)
{
_logQueue.Enqueue(new KeyValuePair<string, string>(key, val));
if (_logQueue.Count() >= _size)
Submit();
}
/// <summary>
/// 写日志 是一个入队操作
/// </summary>
/// <param name="str"></param>
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 文本记录日志
/// <summary>
/// 写入文本记录
/// </summary>
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;
}
/// <summary>
/// 得到日志文本 一个出队操作
/// 将主键相同的数据拼接到一起,减少写入的io操作
/// </summary>
/// <returns></returns>
private ConcurrentDictionary<string, string> GetLogText()
{
ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>();
string key, val;
do
{
KeyValuePair<string, string> kv;
if (_logQueue.TryDequeue(out kv))
{
key = kv.Key;
val = string.Concat(kv.Value, "\r\n----------------------------------------\r\n");
dict.AddOrUpdate(key, val, (k, v) => string.Concat(v + "\r\n" + 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("堆栈信息:\r\n" + 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
{
/// <summary>
/// 自己定义查找方法.参数content是要查询的内容.
/// type是查询条件.如:从文件头部向下查询,从文件尾部向上查询.
/// 如type= RichTextBoxFinds.None 表示从文件头部向下查询.
/// </summary>
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