【C#】C# Winform 定时清理日志
一、前言
在 Winform 开发中经常有这样的需求,在用户执行一些操作不正确时,需要将错误信息反馈给用户,比如:登录密码不正确,无法连接到服务器等,一般常见的用法有两个:
1.弹框
使用 MessageBox.Show("密码错误"); 这样的方式,弹框后,用户必须点击确定后才能执行下一步操作,给用户的体验并不是特别好。
2.在界面中显示错误信息,定时清除
如果是输入框,直接用 ErrorProvider 控件就行了。
如果只是做一些简单的提示信息,那么就要定时清除日志,总不能让错误信息,一直显示在界面上,这容易误导用户,那么就问题就来了,要怎么去定时清理日志呢?
方法1:
使用 Task 去定时清理日志,可以这么写没错,但也有个问题,如果 Task 定时3秒,还没执行完,直接关掉界面,可能会发生报错,不是很安全的写法。
方法2:
使用定时器,这个方法值得推荐,而且相对比较稳定,甚至比上面用异步的方法更简单。
二、定时器
在C#中,定时器有两种,第一种是线程定时器,如果在 Winform 的 UI 线程中使用,会有跨线程问题,第二种,Winform 自带的 Timer 控件,不存在跨线程问题,但也有个问题,在其他线程中使用,可能会出现代码无法执行,所以我们平时在线程的使用上要非常注意。
1.线程定时器
代码
//日志定时器 System.Timers.Timer timer = null; private void Init() { timer = new System.Timers.Timer(3000);//实例化Timer类,设置间隔时间(毫秒); timer.Elapsed += new System.Timers.ElapsedEventHandler(theout);//到达时间的时候执行事件; timer.AutoReset = false;//设置是执行一次(false)还是一直执行(true); } /// <summary> /// 显示日志 /// </summary> /// <param name="val"></param> private void ShowLog(string val) { Label_Log.Text = val; if(timer != null && timer.Enabled) { timer.Enabled = false; } timer.Interval = CoolingTime; timer.Enabled = true; } public void theout(object source, System.Timers.ElapsedEventArgs e) { //跨线程访问 this.Invoke(new MethodInvoker(delegate { Label_Log.Text = string.Empty; })); }
2.Winform定时器
代码:
private System.Windows.Forms.Timer Timer = null; private void Init() { Timer = new System.Windows.Forms.Timer();//实例化Timer类,设置间隔时间(毫秒); Timer.Interval = 3000; Timer.Tick += Timer_Tick;//到达时间的时候执行事件 } //显示日志 private void ShowLog(string log) { Label_Log.Text = log; if (Timer != null && Timer.Enabled) Timer.Enabled = false; Timer.Enabled = true; } private void Timer_Tick(object sender, EventArgs e) { Label_Log.Text = string.Empty; }
个人觉得,还是第二种,更适合Winform开发,所以,我基于上面代码的基础上做了一下封装
三、封装显示日志工具
新建一个Winform项目,界面如下
新建一个类 ShowLogTool,代码如下
using System; using System.Windows.Forms; namespace Utils { public class ShowLogTool { //日志定时器 private static System.Windows.Forms.Timer Timers = null; //日志组件 private static System.Windows.Forms.Label Label_Log; private static void Init() { Timers = new System.Windows.Forms.Timer(); Timers.Tick += Timer_Tick;//到达时间的时候执行事件 } /// <summary> /// 显示日志 /// </summary> /// <param name="control">界面Form的Control</param> /// <param name="label">日志组件Label</param> /// <param name="log">日志内容</param> /// <param name="millisecond">清空日志的间隔时间</param> public static void ShowLog(Control control, Label label, string log, int millisecond, System.Drawing.Color color) { if (control.InvokeRequired) { //Console.WriteLine("非UI线程"); control.Invoke(new MethodInvoker(delegate { ShowLog(label, log, millisecond, color); })); } else { //Console.WriteLine("UI线程"); ShowLog(label, log, millisecond, color); } } private static void ShowLog(Label label, string log, int millisecond, System.Drawing.Color color) { Label_Log = label; Label_Log.ForeColor = color; Label_Log.Text = log; if (Timers != null && Timers.Enabled) Timers.Enabled = false; Timers.Interval = millisecond; Timers.Enabled = true; } private static void Timer_Tick(object sender, EventArgs e) { Label_Log.Text = string.Empty; } static ShowLogTool() { Init(); } private ShowLogTool() { } } }
Form1代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Utils; namespace 显示日志 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //Task.Run(() => //{ // ShowLogTool.ShowLog(this, Label_Log, "我是一个日志", 5000, Color.Red); //}); ShowLogTool.ShowLog(this, Label_Log, "我是一个日志", 3000, Color.Red); } } }
运行后,就可以看到效果了,这里我测试了UI线程,和非UI线程,结果都能满足需求
==================================
2023.12.16
我对上面封装代码进行了优化
新建一个类 FormControlExtensions,用来切换线程
using System; using System.Windows.Forms; public static class FormControlExtensions { /// <summary> /// Invokes actions in UI thread. /// </summary> public static void InvokeIfRequired(this Control control, Action action) { if (control.InvokeRequired) { control.Invoke(new MethodInvoker(action)); } else { action(); } } }
新建一个类 LogShow
using System; using System.Windows.Forms; public class LogShow { //日志组件 public Label Label_Log = null; //日志定时器 private Timer Timers = null; //间隔时间(秒) private int TimeOut = 3; private void Init() { Timers = new Timer(); Timers.Interval = (int)TimeSpan.FromSeconds(TimeOut).TotalMilliseconds; Timers.Tick += Timers_Tick; } private void Timers_Tick(object sender, EventArgs e) { if (Label_Log == null) return; Label_Log.Text = string.Empty; Timers.Enabled = false; } /// <summary> /// 显示日志 /// </summary> /// <param name="message">日志内容</param> public void Show(string message) { if (Label_Log == null) return; FormControlExtensions.InvokeIfRequired(Label_Log, () => { Label_Log.Text = message; if (Timers.Enabled) Timers.Enabled = false; Timers.Enabled = true; }); } /// <summary> /// 显示日志 /// </summary> /// <param name="message">日志内容</param> /// <param name="objs">可变参数</param> public void Show(string message, params object[] objs) { if (Label_Log == null) return; FormControlExtensions.InvokeIfRequired(Label_Log, () => { string content = string.Empty; if (objs != null && objs.Length > 0) content = string.Format(message, objs); else content = message; Label_Log.Text = content; if (Timers.Enabled) Timers.Enabled = false; Timers.Enabled = true; }); } public LogShow() { Init(); } }
用法
在界面拉入一个 Lable 控件,取名为 Label_Log,并讲 Text 属性设置为多个空格
并加入一个按钮,用来显示日志
Form1 代码:
using System; using System.Windows.Forms; namespace 定时清理日志 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private LogShow LogShows = new LogShow(); private void Form1_Load(object sender, EventArgs e) { LogShows.Label_Log = Label_Log; } private void button1_Click(object sender, EventArgs e) { LogShows.Show("我是一个日志"); } } }
运行后
过了3秒,日志会自动消失,如果在显示日志期间再次点击,计时会重新开始。
结束
如果这个帖子对你有用,欢迎关注 + 点赞 + 留言,谢谢
end
原文链接https://blog.csdn.net/qq_38693757/article/details/111881876
猜你喜欢
- 【C#】C# Winform GDI+ 绘图
- 目录一、概述二、绘图1.画直线2.画矩形3.画圆、圆弧4.画扇形5.画多边形6.绘制字符串7.填充图形结束一、概述Graphics类是GDI+技术的一个基本类。GDI+(Graphics Device Interface)是.NET框架的重要组成部分,提供对二维图形图像和文字排版处理的支持。GDI+相关的类分布在下列命名空间中: System.Drawing:提供了最基本的绘图功能(比如画直线、矩形、椭圆等); System.Drawing.Drawing2D: 提供了高级的二维和矢量绘图功能(
- 【C#】C# Winform 文本面板带滚动条
- 在PC软件开发中经常有这样的需求,需要在一个固定大小的面板中显示一些内容,并且面板能上下拖动,将所有的内容完整的展示,有点类似网页上看新闻,如果要在 winfrom 中要如何实现的呢,下面就演示如何实现的吧效果:1.新建一个winform 项目,在界面中拖入一个Panel 将 panel1 的 AutoScroll 设置为 True2.再次拖入一个 Panel ,将高度拉长,这时就自动出现了滚动条,只是此时里面还没有任何内容,下面就在 panel2 中加入一点内容。
- 【C#】C# Winform 多个程序之间的通信(非Scoket)
- 效果功能:打开窗体自动连接主程序,并自动添加到列表,可以向子程序群发消息可以向单个程序单独发送消息在退出程序后,添加的程序列表会自动移除一、概述参考:C# Winfrom程序之间通讯_c# sendmessege copydatastruct 返回多个值_熊思宇的博客-CSDN博客在之前我写过 winform 程序与程序之间的通信,但是这个版本有个问题,那就是只能由两个程序进行通信,同时打开多个程序的话,接收方收到的数据就会一模一样,这次发表这个教程,也就是要解决这个问题。归根结底,还是&nbs
- 【C#】C# Winform DataGridView 数据刷新问题
- 目录一、问题二、创建项目三、绑定空的数据源四、绑定有数据的数据源五、修改绑定的数据源六、解决数据源刷新问题七、解决刷新数据界面闪烁一、问题DataGridView 是比较常用的表格控件,在 DataGridView 中显示数据, 一般使用 dataGridView1.DataSource = 数据源,来绑定数据,数据源可以是 DataTable、List、Dictionary 等,那么如何做到及时刷新数据呢,这里我提出几个问题:1.绑定一个空的数据源,后面向数据源添加数据。2.Data
- 【C#】C# Winfrom 右键菜单
- 目录一、概述二、新建 winform 项目三、给图片控件添加右键菜单四、给菜单添加点击事件五、测试结束一、概述ContextMenuStrip 是 Windows 窗体应用程序中的一个控件,它提供了一个弹出菜单,用于在用户右键单击控件或其他界面元素时显示上下文相关的选项。它通常用于在图形用户界面中提供快捷操作和功能。ContextMenuStrip 控件可以通过在 Visual Studio 的设计器中拖放方式添加到窗体上,或者通过编程方式创建和配置。它可以与其他控件(如按钮、文本框等
- 【C#】C#实现Excel合并单元格数据导入数据集
- 目录功能需求Excel与DataSet的映射关系范例运行环境Excel DCOM 配置设计实现组件库引入方法设计返回值 参数设计打开数据源并计算Sheets拆分合并的单元格创建DataTable将单元格数据写入DataTable总结功能需求将Excel里的worksheet表格导入到DataSet里,是项目应用里常用的一种操作。一般情况下,worksheet是一个标准的二维数组,如下图:我们可以效仿 MS SQL SERVER 的一些基本导入选项,如首行是否包含数据,要导入哪个Shee
- 【C#】C#二分查找(迭代与递归)
- 二分搜索被定义为一种在排序数组中使用的搜索算法,通过重复将搜索间隔一分为二。二分查找的思想是利用数组已排序的信息,将时间复杂度降低到O(log N)。二分查找算法示例 何时在数据结构中应用二分查找的条件: 应用二分查找算法: 1、数据结构必须是有序的。 2、访问数据结构的任何元素都
- 【C#】C# Winfrom 常用功能整合-1
- 目录Winform 最大化遮挡任务栏和全屏显示问题Winfrom 给图片画 矩形,椭圆形,文字Winfrom TabControl选项卡 动态添加,删除,修改Winform ErrorProvider控件Winform 读取Resources图片Winfrom 读取内存条占用大小,硬盘占用大小Winform 全局捕获异常Winform 用线程写入TXT文件,并更新UI和进度Winform 摄像头识别二维码,保存图片Winform 判断窗体是否已打开Winform 动态添加菜单列表,点击切换对应面