C#(064):三种Timer(C# (064): three timers)

一、基于 Windows 的标准计时器(System.Windows.Forms.Timer)

首先注意一点就是:Windows 计时器是为单线程环境设计的。它直接继承自Componet。

Timer控件只有绑定了Tick事件和设置Enabled=True后才会自动计时,停止计时可以用Stop()方法控制,通过Stop()停止之后,如果想重新计时,可以用Start()方法来启动计时器。

Timer控件和它所在的Form属于同一个线程,在这种Timer的EventHandler中可以直接获取和修改UI元素而不会出现问。因为这种Timer实际上就是在UI线程自身上进行调用的。也正是因为这个原因,导致了在Timer的EventHandler里面进行长时间的阻塞调用,将会阻塞界面响应的后果。

这个计时器是使用最简单的一种,只要把工具箱中的Timer控件拖到窗体上,然后设置一下事件和间隔时间等属性就可以了。

    //定义全局变量
    public int currentCount = 0;
     
    private void FrmMain_Load(object sender, EventArgs e)
    {
        //设置Timer控件可用
        this.timer.Enabled = true;
        //设置时间间隔(毫秒为单位)
        this.timer.Interval = 1000;
    }
    
    private void timer_Tick(object sender, EventArgs e)
    {
        currentCount += 1;
        this.txt_Count.Text = currentCount.ToString().Trim();
    }
    
    private void btn_Start_Click(object sender, EventArgs e)
    {
        //开始计时
        this.timer.Start();
    }
    
    private void btn_Stop_Click(object sender, EventArgs e)
    {
        //停止计时
        this.timer.Stop();
    }

二、基于服务器的计时器(System.Timers.Timer)

System.Timers.Timer不依赖窗体,是从线程池唤醒线程,是传统的计时器为了在服务器环境上运行而优化后的更新版本。

定义一个System.Timers.Timer对象,然后绑定Elapsed事件,通过Start()方法来启动计时,通过Stop()方法或者Enable=false停止计时。

AutoReset属性设置是否重复计时(设置为false只执行一次,设置为true可以多次执行)。

在VS的工具箱中没有提供现成的控件,需要手工编码使用此计时器。使用方式有两种:

1、通常情况情况:不使用SynchronizingObject属性

这种方式就是 多线程的方式
,即启动的子线程和主窗体不在一个线程。由于子线程是单独的一个线程,那么就不能访问住窗体中的控件了,需要定义委托,通过Invoke调用委托访问其它线程里面的控件)。

    delegate void SetTextCallback(string text);
    
    void timersTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        //使用代理
        string text = "子线程执行,线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "\r\n";
        SetTextCallback deg = new SetTextCallback(SetText);
        this.Invoke(deg, new object[] { text });
        i++;
    }
    
    private void SetText(string text)
    {
        lblSubThread.Text += text;
    }

2、通过SynchronizingObject属性依附于窗体

通过这种方式来使用,对Timer挂接的EventHandler的调用将会在创建这个UI元素的线程上进行(一般来说就是UI线程)。

此时这种Timer就和System.Windows.Forms.Timer的效果一样:长调用将会阻塞界面。

    void Main()
    {
        System.Timers.Timer timersTimer = new System.Timers.Timer();
        timersTimer.Enabled = false;
        timersTimer.Interval = 100;
    
        //设置执行一次(false)还是一直执行(true),默认为true
        timersTimer.AutoReset = true;
    
        timersTimer.Elapsed += new System.Timers.ElapsedEventHandler(timersTimer_Elapsed);
        timersTimer.SynchronizingObject = this;
    
    }
    
    void timersTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //e.SignalTime
    }

三、线程计时器(System.Threading.Timer)

线程计时器也不依赖窗体,是一种 简单的、轻量级计时器,它使用回调方法而不是使用事件,并由线程池线程提供支持。定义该类时,通过构造函数进行初始化。

定义该类时,主要有四个参数。

  • TimerCallBack: 一个返回值为void,参数为object的委托,也是计时器执行的方法。
  • state: 计时器执行方法的的参数。可以传递一个AutoResetEvent在回调函数中从Main函数发送信息。
  • dueTime: 调用 callback 之前延迟的时间量(以毫秒为单位)。指定 Timeout.Infinite 以防止计时器开始计时。指定零 (0) 以立即启动计时器。
  • Period: 调用callback 的时间间隔(以毫秒为单位)。指定 Timeout.Infinite 可以禁用定期终止。

使用方法如下:

    private void Form1_Load(object sender, EventArgs e)
    {
        System.Threading.Timer threadTimer = new System.Threading.Timer(new System.Threading.TimerCallback(ThreadMethod), null, -1, -1);  //最后两个参数依次为:多久后开始,隔多久执行一次。
    }
    
    public void ThreadMethod(Object state)
    {
        //使用代理
        string text = "子线程执行,线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "\r\n";
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { text });
        i++;
    }

其他:

    //立即开始计时,时间间隔1000毫秒:
    threadTimer.Change(0, 1000);
    //停止计时:
    threadTimer.Change(Timeout.Infinite, 1000);
    //暂停计时:
    threadTimer.Change(-1, -1);

实验的效果和基于服务器的计时器(System.Timers.Timer)的第一种方式是一样的,

当然具体的使用方法和原理是不一样的,最主要的就是 这种方式使用的是代理的方式而不是事件的方式,并且可以不依赖于窗体和组件而单独执行。

————————

一、基于 Windows 的标准计时器(System.Windows.Forms.Timer)

The first thing to note is that the windows timer is designed for a single threaded environment. It inherits directly from componet.

The timer control will automatically time only after the tick event is bound and enabled = true is set. Stopping the timer can be controlled by the stop() method. After stopping through stop(), if you want to restart the timer, you can use the start() method to start the timer.

The timer control and its form belong to the same thread. In this kind of timer’s EventHandler, you can directly obtain and modify UI elements without problems. Because this timer is actually called on the UI thread itself. It is precisely for this reason that a long-time blocking call in the timer’s EventHandler will block the interface response.

This timer is the simplest one to use. Just drag the timer control in the toolbox to the form, and then set the properties such as event and interval time.

    //定义全局变量
    public int currentCount = 0;
     
    private void FrmMain_Load(object sender, EventArgs e)
    {
        //设置Timer控件可用
        this.timer.Enabled = true;
        //设置时间间隔(毫秒为单位)
        this.timer.Interval = 1000;
    }
    
    private void timer_Tick(object sender, EventArgs e)
    {
        currentCount += 1;
        this.txt_Count.Text = currentCount.ToString().Trim();
    }
    
    private void btn_Start_Click(object sender, EventArgs e)
    {
        //开始计时
        this.timer.Start();
    }
    
    private void btn_Stop_Click(object sender, EventArgs e)
    {
        //停止计时
        this.timer.Stop();
    }

二、基于服务器的计时器(System.Timers.Timer)

System. Timers. Timer does not rely on forms. It wakes up threads from the thread pool. It is an updated version of the traditional timer optimized to run in the server environment.

Define a system Timers. Timer object, then bind the elapsed event, start the timing through the start() method, and stop the timing through the stop() method or enable = false.

The autoreset property sets whether the timing is repeated (if set to false, it can be executed only once; if set to true, it can be executed multiple times).

There is no ready-made control in vs toolbox, so you need to code this timer manually. There are two ways to use:

1、通常情况情况:不使用SynchronizingObject属性

This method is called < strong > multithreading < / strong >
, that is, the child thread started is not in the same thread as the main form. Since the sub thread is a separate thread, you cannot access the controls in the form. You need to define a delegate and call the delegate to access the controls in other threads through invoke).

    delegate void SetTextCallback(string text);
    
    void timersTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        //使用代理
        string text = "子线程执行,线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "\r\n";
        SetTextCallback deg = new SetTextCallback(SetText);
        this.Invoke(deg, new object[] { text });
        i++;
    }
    
    private void SetText(string text)
    {
        lblSubThread.Text += text;
    }

2、通过SynchronizingObject属性依附于窗体

Used in this way, the call to the EventHandler attached by timer will be made on the thread that created the UI element (generally speaking, the UI thread).

At this time, this timer is the same as system Windows. Forms. Timer has the same effect: long calls will block the interface.

    void Main()
    {
        System.Timers.Timer timersTimer = new System.Timers.Timer();
        timersTimer.Enabled = false;
        timersTimer.Interval = 100;
    
        //设置执行一次(false)还是一直执行(true),默认为true
        timersTimer.AutoReset = true;
    
        timersTimer.Elapsed += new System.Timers.ElapsedEventHandler(timersTimer_Elapsed);
        timersTimer.SynchronizingObject = this;
    
    }
    
    void timersTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
        //e.SignalTime
    }

三、线程计时器(System.Threading.Timer)

The thread timer does not rely on forms. It is a < strong > simple and lightweight timer. It uses callback methods instead of events, and is supported by thread pool threads. When the class is defined, it is initialized through the constructor

When defining this class, there are four main parameters.

  • Timercallback: a delegate whose return value is void and the parameter is object. It is also a method executed by the timer.
  • State: the parameter of the timer execution method. You can pass an AutoResetEvent to send information from the main function in the callback function.
  • Duetime: the amount of time (in milliseconds) to delay before calling callback. Specify timeout Infinite to prevent the timer from starting. Specify zero (0) to start the timer immediately.
  • Period: the interval (in milliseconds) between calls to callback. Specify timeout Infinite can disable periodic termination.

The usage is as follows:

    private void Form1_Load(object sender, EventArgs e)
    {
        System.Threading.Timer threadTimer = new System.Threading.Timer(new System.Threading.TimerCallback(ThreadMethod), null, -1, -1);  //最后两个参数依次为:多久后开始,隔多久执行一次。
    }
    
    public void ThreadMethod(Object state)
    {
        //使用代理
        string text = "子线程执行,线程ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "\r\n";
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { text });
        i++;
    }

other:

    //立即开始计时,时间间隔1000毫秒:
    threadTimer.Change(0, 1000);
    //停止计时:
    threadTimer.Change(Timeout.Infinite, 1000);
    //暂停计时:
    threadTimer.Change(-1, -1);

The effect of the experiment is the same as the first method of server based timer (system. Timers. Timer),

Of course, the specific use methods and principles are different. The most important thing is that < strong > this method uses the agent method rather than the event method, and can be executed independently without relying on forms and components