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

C# WinForms ProgressBar 進度條完整用法:基本顯示、多執行緒更新、Marquee 模式與自訂繪製

     編輯:關於C語言

基本屬性與模式

屬性說明常用值
Minimum / Maximum進度範圍0 / 100
Value當前進度0~Maximum
StepPerformStep() 遞增量1
Style顯示樣式Blocks(預設)、Continuous、Marquee
MarqueeAnimationSpeedMarquee 模式動畫速度(ms)30~100

基本用法:同步迴圈更新(UI 會凍結)


private void btnSync_Click(object sender, EventArgs e) {
    progressBar1.Minimum = 0;
    progressBar1.Maximum = 100;
    progressBar1.Value = 0;

    for (int i = 0; i <= 100; i++) {
        progressBar1.Value = i;
        Thread.Sleep(50); // 模擬工作,**會凍結 UI**,不建議實務使用
    }
}

正確做法:BackgroundWorker / Task + Progress 非同步更新

方案一:BackgroundWorker (.NET 2.0+ 傳統)


private BackgroundWorker _bw;

private void Form_Load(object sender, EventArgs e) {
    _bw = new BackgroundWorker {
        WorkerReportsProgress = true,
        WorkerSupportsCancellation = true
    };
    _bw.DoWork += Bw_DoWork;
    _bw.ProgressChanged += Bw_ProgressChanged;
    _bw.RunWorkerCompleted += Bw_Completed;
}

private void btnStart_Click(object sender, EventArgs e) {
    if (!_bw.IsBusy) _bw.RunWorkerAsync();
}

private void Bw_DoWork(object sender, DoWorkEventArgs e) {
    var bw = sender as BackgroundWorker;
    for (int i = 0; i <= 100; i++) {
        if (bw.CancellationPending) { e.Cancel = true; return; }
        Thread.Sleep(50); // 真實工作
        bw.ReportProgress(i); // 觸發 ProgressChanged(自動切回 UI 執行緒)
    }
}

private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e) {
    progressBar1.Value = e.ProgressPercentage;
    lblStatus.Text = $"{e.ProgressPercentage}%";
}

private void Bw_Completed(object sender, RunWorkerCompletedEventArgs e) {
    if (e.Cancelled) lblStatus.Text = "已取消";
    else if (e.Error != null) lblStatus.Text = "錯誤: " + e.Error.Message;
    else lblStatus.Text = "完成!";
}

方案二:Task + IProgress (現代 .NET 4.5+ 推薦)


private async void btnAsync_Click(object sender, EventArgs e) {
    btnAsync.Enabled = false;
    progressBar1.Value = 0;
    progressBar1.Style = ProgressBarStyle.Continuous;

    var progress = new Progress(v => {
        progressBar1.Value = v;
        lblStatus.Text = $"{v}%";
    });

    try {
        await Task.Run(() => DoHeavyWork(progress));
        lblStatus.Text = "完成!";
    } catch (Exception ex) {
        lblStatus.Text = "錯誤: " + ex.Message;
    } finally {
        btnAsync.Enabled = true;
    }
}

private void DoHeavyWork(IProgress progress) {
    for (int i = 0; i <= 100; i++) {
        Thread.Sleep(50); // 真實工作
        progress.Report(i); // 自動捕獲 SynchronizationContext 回 UI 執行緒
    }
}

Marquee 模式:不確定進度(如連線中、查詢中)


private void StartIndeterminate() {
    progressBar1.Style = ProgressBarStyle.Marquee;
    progressBar1.MarqueeAnimationSpeed = 50;
}

private void StopIndeterminate() {
    progressBar1.Style = ProgressBarStyle.Blocks;
    progressBar1.MarqueeAnimationSpeed = 0;
    progressBar1.Value = 0;
}

雙層進度條:外層總進度 + 內層當前檔案


// UI: progressOverall (總進度), progressCurrent (單檔進度)

private async Task ProcessFilesAsync(string[] files, IProgress<(int overall, int current)> progress) {
    for (int i = 0; i < files.Length; i++) {
        // 模擬單檔處理
        for (int p = 0; p <= 100; p += 10) {
            await Task.Delay(50);
            progress.Report(( (i * 100) / files.Length, p ));
        }
        progress.Report(( (i + 1) * 100 / files.Length, 100 ));
    }
}

// 使用
var progress = new Progress<(int overall, int current)>(t => {
    progressOverall.Value = t.overall;
    progressCurrent.Value = t.current;
});
await ProcessFilesAsync(fileList, progress);

自訂繪製:OwnerDraw 進度條(顯示文字、顏色漸層)


public class CustomProgressBar : ProgressBar {
    public CustomProgressBar() {
        SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
    }

    protected override void OnPaint(PaintEventArgs e) {
        Rectangle rect = ClientRectangle;
        Graphics g = e.Graphics;

        // 背景
        using (var brush = new SolidBrush(SystemColors.Control)) g.FillRectangle(brush, rect);

        // 進度填滿(漸層)
        int width = (int)(rect.Width * ((double)Value / Maximum));
        if (width > 0) {
            Rectangle progRect = new Rectangle(0, 0, width, rect.Height);
            using (var lgb = new LinearGradientBrush(progRect, Color.LimeGreen, Color.ForestGreen, LinearGradientMode.Horizontal))
                g.FillRectangle(lgb, progRect);
        }

        // 文字置中
        string text = $"{Value}%";
        SizeF sz = g.MeasureString(text, Font);
        float x = (rect.Width - sz.Width) / 2;
        float y = (rect.Height - sz.Height) / 2;
        using (var brush = new SolidBrush(Color.Black)) g.DrawString(text, Font, brush, x, y);
    }
}

使用:工具箱右鍵「選擇項目」→ 加入自訂控制項,或直接在程式碼 `new CustomProgressBar()`。

常見問題與解決

問題原因解決
進度條不更新/卡住長時間工作在 UI 執行緒移至 BackgroundWorker/Task,用 ReportProgress/IProgress
Value 設定超出範圍例外Maximum 未設或計算錯誤設值前 clamp:`Math.Min(Math.Max(val, Minimum), Maximum)`
Marquee 不動畫Visual Styles 未啟用Program.cs 加 `Application.EnableVisualStyles();`
跨執行緒存取例外直接在工作執行緒設 Value用 `Invoke` 或 `IProgress` 自動封送
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved