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 | 跨執行緒資料同步 | 鎖定範圍越小越好,避免死結 |
VirtualMode | DataGridView 虛擬模式,按需查詢資料 | 資料量 > 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 替換引用
grid.Rows.Add() → InvalidOperationException。Invoke 或 BeginInvoke 封裝。Invoke 導致 UI 卡頓 → 批次累積 + Timer 節流。ArgumentException 或資料毀損。lock 或改用 ConcurrentQueue + TryDequeue。SuspendLayout → 大量新增列時閃爍、CPU 飆高。即時刷新 UI 的核心模式是 背景產生 → 佇列緩衝 → UI 定時批次消費。配合 SuspendLayout、VirtualMode、ConcurrentQueue,可支援每秒百筆以上的資料流而不凍結介面。專案中請依資料量與更新頻率選擇適當策略,並務必加入取消權杖 (CancellationToken) 實現優雅關閉。