You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Framework 4.8(C#7.3)中DataGridView多单元格倒计时实现求助

.NET Framework 4.8 DataGridView多倒计时与文件读写实现方案

一、整体思路确认

你的思路完全可行:用CSV/TXT作为轻量存储,程序启动时加载数据到内存,运行时通过全局Timer统一更新所有行的倒计时状态,新增数据时同步写入文件。这种方案适合小规模数据场景,无需复杂数据库。

二、DataGridView列配置

先手动配置列(或代码初始化),对应需求的5列:

  • 代码列:设为可编辑的DataGridViewTextBoxColumn,允许用户输入
  • 开始日期列:DataGridViewTextBoxColumn,只读,格式设为yyyy-MM-dd HH:mm:ss
  • 结束日期列:DataGridViewTextBoxColumn,只读,格式同上
  • 倒计时列:DataGridViewTextBoxColumn,只读,显示HH:mm:ss格式剩余时间
  • 状态列:DataGridViewTextBoxColumn,只读,显示“空闲/占用”

代码初始化示例(Form_Load事件中):

private void Form1_Load(object sender, EventArgs e)
{
    // 初始化列
    dataGridView1.Columns.AddRange(new DataGridViewColumn[]
    {
        new DataGridViewTextBoxColumn { Name = "Code", HeaderText = "代码", Width = 100 },
        new DataGridViewTextBoxColumn { Name = "StartDate", HeaderText = "开始日期", Width = 150, ReadOnly = true, DefaultCellStyle = { Format = "yyyy-MM-dd HH:mm:ss" } },
        new DataGridViewTextBoxColumn { Name = "EndDate", HeaderText = "结束日期", Width = 150, ReadOnly = true, DefaultCellStyle = { Format = "yyyy-MM-dd HH:mm:ss" } },
        new DataGridViewTextBoxColumn { Name = "Countdown", HeaderText = "倒计时", Width = 100, ReadOnly = true },
        new DataGridViewTextBoxColumn { Name = "Status", HeaderText = "状态", Width = 80, ReadOnly = true }
    });

    // 加载本地CSV数据
    LoadDataFromCsv(@"tasks.csv");

    // 启动全局倒计时Timer,1秒触发一次
    var timer = new System.Windows.Forms.Timer { Interval = 1000 };
    timer.Tick += Timer_Tick;
    timer.Start();
}

三、独立倒计时实现(全局Timer方案)

用单个Timer统一更新所有行,避免多Timer资源浪费:

private void Timer_Tick(object sender, EventArgs e)
{
    foreach (DataGridViewRow row in dataGridView1.Rows)
    {
        // 跳过新行
        if (row.IsNewRow) continue;

        if (DateTime.TryParse(row.Cells["EndDate"].Value?.ToString(), out DateTime endDate))
        {
            TimeSpan remaining = endDate - DateTime.Now;
            if (remaining > TimeSpan.Zero)
            {
                // 更新倒计时和状态
                row.Cells["Countdown"].Value = $"{remaining.Hours:D2}:{remaining.Minutes:D2}:{remaining.Seconds:D2}";
                row.Cells["Status"].Value = "占用";
            }
            else
            {
                row.Cells["Countdown"].Value = "已结束";
                row.Cells["Status"].Value = "空闲";
            }
        }
    }
}

四、输入代码自动填充数据

监听CellEndEdit事件,当用户完成代码输入后自动填充日期并保存:

private void DataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    // 仅处理代码列(索引0)
    if (e.ColumnIndex != dataGridView1.Columns["Code"].Index || e.RowIndex < 0) return;

    DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
    string code = row.Cells["Code"].Value?.ToString()?.Trim();
    if (string.IsNullOrEmpty(code)) return;

    // 避免重复填充
    if (row.Cells["StartDate"].Value != null) return;

    // 填充开始、结束日期
    DateTime now = DateTime.Now;
    row.Cells["StartDate"].Value = now;
    row.Cells["EndDate"].Value = now.AddMinutes(45);

    // 立即保存到CSV
    SaveDataToCsv(@"tasks.csv");
}

五、CSV文件读写实现

写入全表到CSV

private void SaveDataToCsv(string filePath)
{
    using (StreamWriter sw = new StreamWriter(filePath, false, Encoding.UTF8))
    {
        // 写入表头
        sw.WriteLine("Code,StartDate,EndDate");

        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
            if (row.IsNewRow) continue;

            string code = row.Cells["Code"].Value?.ToString() ?? "";
            string startDate = row.Cells["StartDate"].Value?.ToString() ?? "";
            string endDate = row.Cells["EndDate"].Value?.ToString() ?? "";

            // 处理含逗号的内容(用双引号包裹)
            code = code.Contains(",") ? $"\"{code}\"" : code;
            sw.WriteLine($"{code},{startDate},{endDate}");
        }
    }
}

从CSV加载数据

private void LoadDataFromCsv(string filePath)
{
    if (!File.Exists(filePath)) return;

    dataGridView1.Rows.Clear();

    using (StreamReader sr = new StreamReader(filePath, Encoding.UTF8))
    {
        // 跳过表头
        sr.ReadLine();

        string line;
        while ((line = sr.ReadLine()) != null)
        {
            string[] parts = line.Split(',');
            if (parts.Length < 3) continue;

            // 解析带双引号的内容
            string code = parts[0].Trim('"');
            string startDate = parts[1];
            string endDate = parts[2];

            dataGridView1.Rows.Add(code, startDate, endDate, "", "");
        }
    }

    // 加载后立即触发一次倒计时更新
    Timer_Tick(null, null);
}

六、关键细节说明

  1. 日期格式统一:读写CSV时用yyyy-MM-dd HH:mm:ss格式,避免解析错误
  2. 重复填充判断:在CellEndEdit中判断开始日期是否已填充,防止重复触发
  3. 新行处理:遍历时跳过DataGridView的默认新行,避免空数据错误
  4. 编码问题:读写CSV用UTF8编码,避免中文乱码

内容的提问来源于stack exchange,提问作者Manuele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 23:11:13