目录
前言
开发环境:
IDE:Visual Studio 2026
语言:C#
框架:.NET Framework 4.5
UI:WinForms
本系列上一篇文章我们实现了开机自启功能,让程序可以在系统启动时自动运行。然而,很多工具类软件还需要在特定时间自动执行任务(比如每天下午6点同步数据)。本篇将教你如何实现定时自动更新功能,让程序在用户设定的时间自动完成数据同步。
一、为什么需要定时更新?
对于数据同步类应用,如果每次都要用户手动点击“同步”,不仅繁琐,还容易忘记。实现定时更新后,程序可以在用户指定的时间(如下班后)自动完成数据同步,既保证了数据的时效性,又无需用户干预。
二、实现原理
Windows Forms 提供了 System.Windows.Forms.Timer 控件,它会在 UI 线程上周期性触发 Tick 事件。我们可以利用它实现定时任务:
- 用户通过复选框
chkAutoSync开启自动同步功能,并通过DateTimePicker控件dtpAutoSyncTime选择同步时间(如 18:00)。 - 程序启动时,读取用户上次保存的设置,并根据当前时间计算距离下一个同步时刻还有多少毫秒,将定时器的
Interval设置为该值。 - 当定时器
Tick事件触发时,执行数据同步(静默模式,不弹出消息框),然后重新计算下一次执行时间(即明天同一时刻)。 - 用户改变勾选状态或修改时间时,立即重新计算定时器间隔,并保存设置。
三、实现步骤
1. 设计界面
在窗体上添加两个控件:
- CheckBox:命名为
chkAutoSync,Text 设为“自动同步”。 - DateTimePicker:命名为
dtpAutoSyncTime,用于选择时间。
为了让 DateTimePicker 只显示小时和分钟(不显示日期),需要进行以下设置:
- 在属性窗口中将
Format属性改为Custom。 - 将
CustomFormat属性设置为"HH:mm"(注意大小写,HH 表示24小时制,mm 表示分钟)。 - 显示时间调整按钮,将
ShowUpDown设为True。

界面效果如图所示:

2. 添加字段与定时器
在 MainForm 类中添加以下字段:
// 自动同步定时器
private System.Windows.Forms.Timer autoSyncTimer;
// 防止自动同步重入
private bool isAutoSyncRunning = false;
// 防止在设置保存时重复触发事件
private bool isUpdatingAutoSyncSettings = false;
注意:由于项目中可能同时引用了
System.Threading.Timer或其他命名空间,建议使用完全限定名System.Windows.Forms.Timer以避免歧义。
3. 在构造函数中初始化定时器并加载设置
public MainForm()
{
InitializeComponent();
// ... 其他初始化(如 syncService、DPI 适配等)...
// 初始化自动同步定时器
autoSyncTimer = new System.Windows.Forms.Timer();
autoSyncTimer.Tick += AutoSyncTimer_Tick;
// 加载保存的设置
chkAutoSync.Checked = Properties.Settings.Default.AutoSyncEnabled;
dtpAutoSyncTime.Value = DateTime.Parse(Properties.Settings.Default.AutoSyncTime);
// 如果自动同步已开启,启动定时器
if (chkAutoSync.Checked)
{
SetAutoSyncTimer();
}
}
4. 实现计算下次执行时间的方法
/// <summary>
/// 根据用户设定的时间设置定时器间隔并启动
/// </summary>
private void SetAutoSyncTimer()
{
// 如果未勾选自动同步,则停止定时器
if (!chkAutoSync.Checked)
{
autoSyncTimer.Stop();
return;
}
DateTime now = DateTime.Now;
// 构造今天的同步目标时间(只取用户设定的小时和分钟)
DateTime target = new DateTime(now.Year, now.Month, now.Day,
dtpAutoSyncTime.Value.Hour,
dtpAutoSyncTime.Value.Minute, 0);
// 如果今天的目标时间已经过了,则设为明天
if (target <= now)
{
target = target.AddDays(1);
}
// 计算相差的毫秒数,并设置定时器间隔
double intervalMs = (target - now).TotalMilliseconds;
autoSyncTimer.Interval = (int)intervalMs;
autoSyncTimer.Start();
}
5. 实现定时器的 Tick 事件(自动同步执行)
private async void AutoSyncTimer_Tick(object sender, EventArgs e)
{
// 先停止定时器,避免在执行过程中重复触发
autoSyncTimer.Stop();
if (isAutoSyncRunning) return;
isAutoSyncRunning = true;
try
{
// 调用同步服务,静默模式(不弹消息框)
await syncService.SyncData(silent: true);
}
finally
{
isAutoSyncRunning = false;
// 同步完成后,重新计算下一次执行时间(明天同一时刻)
SetAutoSyncTimer();
}
}
6. 处理用户交互事件
为 chkAutoSync 添加 CheckedChanged 事件:
private void chkAutoSync_CheckedChanged(object sender, EventArgs e)
{
// 防止在保存设置时重复触发
if (isUpdatingAutoSyncSettings) return;
try
{
isUpdatingAutoSyncSettings = true;
bool enabled = chkAutoSync.Checked;
if (enabled)
SetAutoSyncTimer();
else
autoSyncTimer.Stop();
// 保存设置
Properties.Settings.Default.AutoSyncEnabled = enabled;
Properties.Settings.Default.Save();
}
finally
{
isUpdatingAutoSyncSettings = false;
}
}
在控件chkAutoSync的事件设置CheckedChanged的值为chkAutoSync_CheckedChanged

为 dtpAutoSyncTime 添加 ValueChanged 事件:
private void dtpAutoSyncTime_ValueChanged(object sender, EventArgs e)
{
if (isUpdatingAutoSyncSettings) return;
try
{
isUpdatingAutoSyncSettings = true;
// 保存用户选择的时间
Properties.Settings.Default.AutoSyncTime = dtpAutoSyncTime.Value.ToString();
Properties.Settings.Default.Save();
// 如果自动同步已开启,重新计算定时器(使新的时间生效)
if (chkAutoSync.Checked)
SetAutoSyncTimer();
}
finally
{
isUpdatingAutoSyncSettings = false;
}
}
在控件dtpAutoSyncTime的事件设置ValueChanged的值为dtpAutoSyncTime_ValueChanged

8. 添加应用程序设置
在项目属性 → 设置中,添加两个用户设置:
| 名称 | 类型 | 范围 | 默认值 |
|---|---|---|---|
| AutoSyncEnabled | bool | 用户 | False |
| AutoSyncTime | string | 用户 | 18:00:00 |
这样,用户的选择会被保存,下次启动程序时自动恢复。

四、测试验证
- 勾选自动同步:勾选
chkAutoSync,观察定时器是否按当前时间计算并启动(可在代码中输出Interval验证)。 - 修改同步时间:将时间改为稍后的几分钟(如当前时间+2分钟),等待定时器触发,观察程序是否自动执行同步(注意同步服务内部会有日志输出,可以设置断点或查看输出窗口)。
- 重启程序:关闭程序后重新运行,查看
chkAutoSync是否保持勾选状态,且定时器按预期启动。 - 跨天测试:如果设定的时间已经过了当天,定时器应被设置为明天同一时间。
五、注意事项
- 定时器的精度:
System.Windows.Forms.Timer的精度约为 10-20 毫秒,对于小时级别的任务完全足够。 - UI 线程阻塞:如果
SyncData方法执行时间较长(如网络请求、文件操作),可能会阻塞 UI 线程,导致界面无响应。建议在服务内部使用异步方法,我们已经将SyncData设计为async Task,不会阻塞 UI。 - 系统时间更改:如果用户在程序运行期间修改了系统时间,定时器可能不会按预期执行。但正常使用场景下极少发生,可忽略。
- 静默同步:自动同步时我们使用了
silent: true,服务内部不会弹出任何消息框,但会通过事件报告进度和错误。如有需要,可以在 UI 层记录日志或显示通知(如托盘气泡)。 - 定时器的停止与重启:我们在
Tick事件开头先停止定时器,执行完同步后再重新启动,这样可以避免在同步过程中再次触发(同步可能耗时)。同步完成后重新计算间隔,确保下一个周期正确。
六、总结
通过本文,我们成功实现了定时自动更新功能,用户只需勾选自动同步并设定时间,程序就会每天在指定时间静默执行数据同步。结合上一篇的开机自启,你的程序已经具备了后台运行的核心能力。
在下一篇中,我们将继续完善程序的用户体验,实现后台运行(系统托盘),让程序在最小化时隐藏到托盘区域,进一步提升易用性。敬请期待!
后记
文中所有代码均已验证,可直接复制到你的项目中,如有任何疑问,欢迎在评论区留言交流。
喜欢的点个关注吧><!祝你永无bug~
/*
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O\ = /O
____/`---'\____
.' \\| |// `.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : `- \`.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG
*/

自动定时更新&spm=1001.2101.3001.5002&articleId=159652011&d=1&t=3&u=b08fc5f149604b01b723f5161e6e089e)
752

被折叠的 条评论
为什么被折叠?



