找回密码
 立即注册
首页 业界区 业界 一种winform实时刷新日志内容的方法

一种winform实时刷新日志内容的方法

账暴 4 小时前
做上位机,经常会有实时刷新日志内容的需求,比如接收串口消息、MQTT接收消息,常用的方法是Invoke函数 + TextBox.AppendText,比如
  1. Invoke((new Action(() =>
  2. {
  3.         String msg = "串口消息" + Environment.NewLine;
  4.     txtReceiveMessage.AppendText(string.Format("{0} - {1}",DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),msg));
  5. })));
复制代码
但是这种方式有两个弊端,一是日志长度靠TextBox.MaxLength属性控制,不能准确到行;二来消息只能逐个向后添加,不好调整顺序。
想要更灵活地刷新日志内容,可以使用AsyncOperation类与数据绑定功能。
AsyncOperation :C#中用来跟踪异步操作的生存期的类,其中的Post函数,可以从异步操作中向主进程发送消息。
数据绑定:C#中一种非常强大的功能,它允许开发者将控件属性与数据源连接起来,实现自动更新和同步。
默认情况下,绑定在TextBox、Label上的数据,只有在主进程上改动才能实时反应到界面上,跨线程操作会报错,这时则需要通过AsyncOperation类把“数据改动”这个消息发送到主界面上,才能正常展示,示例代码如下:

  • 先创建一个AsyncProperty类
  1. public class AsyncProperty : INotifyPropertyChanged
  2. {
  3.     protected AsyncOperation operation;
  4.     public event PropertyChangedEventHandler PropertyChanged;
  5.     public AsyncProperty()
  6.     {
  7.         operation = AsyncOperationManager.CreateOperation(null);
  8.     }
  9.         // 通过Post函数,将属性更改消息发送到主进程
  10.     public void PostProperty(string propertyName)
  11.     {
  12.         operation.Post(new System.Threading.SendOrPostCallback(_ =>
  13.         {
  14.             if (PropertyChanged != null)
  15.                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  16.         }), null);
  17.     }
  18. }
复制代码

  • 继承AsyncProperty类,创建一个日志类LogContent
  1. public class LogContent : AsyncProperty
  2. {
  3.     // 设置日志最大行数
  4.     private int maxLine = 200;
  5.     private int line = 0;
  6.     private string _content = string.Empty;
  7.     public string Content
  8.     {
  9.         get { return _content; }
  10.     }
  11.     public void InsertLog(string content)
  12.         {
  13.             line++;
  14.             StringBuilder sb = new StringBuilder();
  15.             sb.Append(content);
  16.             sb.Append("\r\n");
  17.             if (line > maxLine)
  18.             {
  19.                 sb.Append(_content.Substring(0, indexOfNth(_content, maxLine, '\n', 1)));
  20.             }
  21.             else
  22.             {
  23.                 sb.Append(_content);
  24.             }
  25.        
  26.             _content = sb.ToString();
  27.             PostProperty(nameof(Content));
  28.         }
  29.     public void ClearLog()
  30.     {
  31.         line = 0;
  32.         _content = string.Empty;
  33.         PostProperty(nameof(Content));
  34.     }
  35. }
复制代码

  • 把LogContent.Content绑定到TextBox.Text上即可
  1. public partial class Form1 : Form
  2. {
  3.     LogContent logContent;
  4.     public Form1()
  5.     {
  6.         InitializeComponent();
  7.         logContent = new LogContent();
  8.         textBox1.DataBindings.Add("Text", logContent, nameof(logContent.Content));
  9.     }
  10.     private void btnLog_Click(object sender, EventArgs e)
  11.     {
  12.         Thread thread = new Thread(WriteLog);
  13.         thread.IsBackground = true;
  14.         thread.Start();
  15.     }
  16.     private void WriteLog()
  17.     {
  18.         for (int i = 0; i < 500; i++)
  19.         {
  20.             Thread.Sleep(100);
  21.             logContent.InsertLog(DateTime.Now.ToString("yyyyMMddHHmmssfff"));
  22.         }
  23.     }
  24. }
复制代码
此时,跨线程调用的WriteLog函数,会将日志倒序实时刷新到界面上。
1.gif


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册