首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

C# ThreadPool 即時刷新 DataGridView/ListView 完整實作模式

     編輯:更多程式設計知識

核心挑戰

  • 背景執行緒**不能直接存取 UI 控制項** (跨執行緒例外)。
  • 高頻更新需**批次/節流**,避免 UI 執行緒塞住。
  • 資料來源可能來自多執行緒,**需鎖定**保護一致性。

推薦架構:Producer-Consumer + UI 節流


using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;

public class RealTimeGridUpdater {
    readonly DataGridView _grid;
    readonly object _lock = new();
    readonly List _pending = new();
    readonly System.Windows.Forms.Timer _uiTimer = new() { Interval = 200 }; // 5 FPS

    public RealTimeGridUpdater(DataGridView grid) {
        _grid = grid;
        _uiTimer.Tick += FlushToUi;
        _uiTimer.Start();
    }

    // 背景執行緒呼叫:產生資料
    public void OnDataReceived(IEnumerable newData) {
        lock (_lock) {
            _pending.AddRange(newData);
        }
    }

    // UI 執行緒定時消費
    void FlushToUi(object sender, EventArgs e) {
        List batch;
        lock (_lock) {
            if (_pending.Count == 0) return;
            batch = new List(_pending);
            _pending.Clear();
        }
        _grid.Invoke((Action)(() => {
            _grid.SuspendLayout();
            foreach (var v in batch) AddOrUpdateRow(v);
            _grid.ResumeLayout();
        }));
    }

    void AddOrUpdateRow(VehicleInfo v) {
        // 簡易示範:直接新增,實務可用 Dictionary 更新既有列
        int idx = _grid.Rows.Add();
        var row = _grid.Rows[idx];
        row.Cells["MCUID"].Value = v.MCUID;
        row.Cells["VehicleNo"].Value = v.VehicleNo;
        row.Cells["Online"].Value = v.Online;
        row.Cells["Velocity"].Value = v.Velocity;
        // ... 其他欄位
    }
}

// 背景工作範例
ThreadPool.QueueUserWorkItem(_ => {
    while (!cts.Token.IsCancellationRequested) {
        var data = FetchFromGpsService(); // 耗時 I/O
        updater.OnDataReceived(data);
        Thread.Sleep(1000);
    }
});

關鍵技術點解析

技術用途注意事項
Control.Invoke同步切換到 UI 執行緒會阻塞呼叫執行緒,高頻改用 BeginInvoke 或批次
SuspendLayout/ResumeLayout批次更新時暫停版面重算大幅減少閃爍與 CPU 佔用
Timer (WinForms)UI 執行緒定時器,天然單執行緒Interval 建議 100-500ms,避免過度刷新
lock / ConcurrentQueue跨執行緒資料同步鎖定範圍越小越好,避免死結
VirtualModeDataGridView 虛擬模式,按需查詢資料資料量 > 10k 列時必須啟用

進階:虛擬模式 + 背景快取


_grid.VirtualMode = true;
_grid.CellValueNeeded += (s, e) => {
    var item = _cache[e.RowIndex]; // _cache 為 List,背景更新時 Interlocked.Exchange 替換
    var prop = typeof(VehicleInfo).GetProperty(_grid.Columns[e.ColumnIndex].DataPropertyName);
    e.Value = prop?.GetValue(item);
};
// 背景執行緒定期重建 _cache 並 Interlocked.Exchange 替換引用

常見錯誤與修正

  1. 直接在背景執行緒 grid.Rows.Add() → InvalidOperationException。
    修正:用 Invoke 或 BeginInvoke 封裝。
  2. 頻繁 Invoke 導致 UI 卡頓 → 批次累積 + Timer 節流。
  3. 未鎖定共享集合 → ArgumentException 或資料毀損。
    修正:lock 或改用 ConcurrentQueue + TryDequeue。
  4. 忘記 SuspendLayout → 大量新增列時閃爍、CPU 飆高。

結語

即時刷新 UI 的核心模式是 背景產生 → 佇列緩衝 → UI 定時批次消費。配合 SuspendLayout、VirtualMode、ConcurrentQueue,可支援每秒百筆以上的資料流而不凍結介面。專案中請依資料量與更新頻率選擇適當策略,並務必加入取消權杖 (CancellationToken) 實現優雅關閉。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved