C# winform中自定义精确定时器(经测试稳定可靠)

时间:2023-01-22 08:55:45

原C#的定时器时间越长,误差越大。

在主动请求设备数据的使用,使用C#的几种自带定时器导致每天都会丢失几条数据。

经测试使用自定义的定时器可完全解决此问题。

使用方法:

MillisecondTimer _sysTimer;

_sysTimer = new MillisecondTimer();
_sysTimer.Tick += sysTimer_Tick; ;
_sysTimer.Interval = 1000; //每秒执行
_sysTimer.Start();

private void sysTimer_Tick(object sender, EventArgs e)
{

//需要定时执行的内容

}

自定义类(MillisecondTimer.cs)如下:

using System;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace TEST
{
public sealed class MillisecondTimer : IComponent, IDisposable
{

private static TimerCaps caps;
private int interval;
private bool isRunning;
private int resolution;
private TimerCallback timerCallback;
private int timerID;

public int Interval
{
get
{
return this.interval;
}
set
{
if ((value < caps.periodMin) || (value > caps.periodMax))
{
throw new Exception("超出计时范围!");
}
this.interval = value;
}
}

/// <summary>
///
/// </summary>
public bool IsRunning
{
get
{
return this.isRunning;
}
}

/// <summary>
///
/// </summary>
public ISite Site
{
set;
get;
}

public event EventHandler Disposed; // 这个事件实现了IComponet接口
public event EventHandler Tick;

static MillisecondTimer()
{
timeGetDevCaps(
ref caps, Marshal.SizeOf(caps));
}

public MillisecondTimer()
{
this.interval = caps.periodMin; //
this.resolution = caps.periodMin; //

this.isRunning = false;
this.timerCallback = new TimerCallback(this.TimerEventCallback);

}

public MillisecondTimer(IContainer container)
:
this()
{
container.Add(
this);
}

~MillisecondTimer()
{
timeKillEvent(
this.timerID);
}

public void Start()
{
if (!this.isRunning)
{
this.timerID = timeSetEvent(this.interval, this.resolution, this.timerCallback, 0, 1); // 间隔性地运行

if (this.timerID == 0)
{
throw new Exception("无法启动计时器");
}
this.isRunning = true;
}
}

public void Stop()
{
if (this.isRunning)
{
timeKillEvent(
this.timerID);
this.isRunning = false;
}
}

/// <summary>
/// 实现IDisposable接口
/// </summary>
public void Dispose()
{
timeKillEvent(
this.timerID);
GC.SuppressFinalize(
this);
EventHandler disposed
= this.Disposed;
if (disposed != null)
{
disposed(
this, EventArgs.Empty);
}
}


//*************************************************** 内部函数 ******************************************************************
[DllImport("winmm.dll")]
private static extern int timeSetEvent(int delay, int resolution, TimerCallback callback, int user, int mode);


[DllImport(
"winmm.dll")]
private static extern int timeKillEvent(int id);


[DllImport(
"winmm.dll")]
private static extern int timeGetDevCaps(ref TimerCaps caps, int sizeOfTimerCaps);
// The timeGetDevCaps function queries the timer device to determine its resolution.



private void TimerEventCallback(int id, int msg, int user, int param1, int param2)
{
if (this.Tick != null)
{
this.Tick(this, null); // 引发事件
}
}


//*************************************************** 内部类型 ******************************************************************

private delegate void TimerCallback(int id, int msg, int user, int param1, int param2); // timeSetEvent所对应的回调函数的签名


/// <summary>
/// 定时器的分辨率(resolution)。单位是ms,毫秒
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct TimerCaps
{
public int periodMin;
public int periodMax;
}

}
}