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

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊思宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值