本文整理《Head First C#》中文版第二章關於迴圈控制、延遲問題與視覺化程式設計的關鍵概念與練習解答。
當在 while 迴圈中巢狀 for 迴圈執行動畫或延遲效果時,會遇到回應性問題:
// 問題代碼
while (visible == true)
{
for (int i = 0; i < 255; i++)
{
// 改變顏色
// 此處無法檢查 visible 狀態
}
for (int i = 254; i >= 0; i--)
{
// 改變顏色
}
}
// 使用者點擊關閉視窗,程式卡在 for 迴圈無法退出
// 修正版
bool visible = true;
while (visible)
{
for (int i = 0; i < 255 && visible; i++)
{
// 改變顏色
// 此處可檢查 visible
Application.DoEvents(); // 讓 UI 執行緒處理訊息
}
for (int i = 254; i >= 0 && visible; i--)
{
// 改變顏色
Application.DoEvents();
}
}
// 關閉視窗時設定 visible = false
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
visible = false;
}
| 技術 | 用途 | 注意事項 |
|---|---|---|
| Application.DoEvents() | 處理待處理的 Windows 訊息 | 可能導致重入問題,謹慎使用 |
| 迴圈條件加入旗標 | 讓迴圈可提前退出 | 需配合 volatile 或記憶體柵欄 |
| CancellationToken | 現代取消模式 | 適用 Task/async 非同步程式 |
| BackgroundWorker | 舊版背景執行緒 | 已過時,建議用 Task.Run |
using System.Threading;
using System.Threading.Tasks;
public class ModernAnimation
{
private CancellationTokenSource _cts;
private Task _animationTask;
public async Task StartAnimationAsync()
{
_cts = new CancellationTokenSource();
_animationTask = RunAnimationAsync(_cts.Token);
await _animationTask;
}
public void StopAnimation()
{
_cts?.Cancel();
}
private async Task RunAnimationAsync(CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
// 漸變顏色 0-255
for (int i = 0; i < 255 && !token.IsCancellationRequested; i++)
{
UpdateColor(i);
await Task.Delay(10, token); // 非阻塞延遲
}
// 漸變顏色 255-0
for (int i = 254; i >= 0 && !token.IsCancellationRequested; i--)
{
UpdateColor(i);
await Task.Delay(10, token);
}
}
}
catch (OperationCanceledException)
{
// 正常取消
}
}
private void UpdateColor(int value)
{
// 更新 UI 控制項顏色
// 若在非 UI 執行緒,需用 Invoke/BeginInvoke
}
}
| 錯誤 | 原因 | 正確寫法 |
|---|---|---|
| if (x = 5) | 指派而非比較 | if (x == 5) |
| while (true) 無退出 | 無限迴圈凍結 UI | 加入取消條件或用 Timer |
| 迴圈中無 DoEvents | UI 凍結無法回應 | 加入 DoEvents 或改用非同步 |
| 變數未初始化 | 編譯錯誤 | int x = 0; 或 var x = 0; |
第二章核心在於建立「程式 = 指令序列」的心智模型:指令在方法中執行,方法屬於類別,類別屬於命名空間。迴圈與條件控制流程,變數儲存資料。UI 程式設計需注意執行緒阻塞問題,現代開發優先使用 async/await 與 CancellationToken 取代 DoEvents 與旗標變數。理解這些基礎概念,是後續學習物件導向、事件驅動、非同步程式設計的基石。