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

C# 自訂 ListView 控制項實作資料列進度條

     編輯:關於C語言

WinForms 內建的 ListView 雖支援 OwnerDraw 自繪,但並未提供「在特定欄位直接顯示進度條」的開箱即用功能。本文示範如何繼承 ListView 並覆寫 OnDrawSubItem,以最少程式碼實現「欄位文字為數值時自動繪製進度條、支援自訂顏色、百分比文字置中」的效果,並搭配 Timer 展示動態更新。

核心類別:ListViewEx

public partial class ListViewEx : ListView
{
    // 進度條欄位索引(-1 表示不啟用)
    public int ProgressColumnIndex { get; set; } = -1;

    // 進度條顏色
    public Color ProgressColor { get; set; } = Color.Red;
    // 進度文字顏色
    public Color ProgressTextColor { get; set; } = Color.Black;

    public ListViewEx()
    {
        InitializeComponent();
        // 必須開啟 OwnerDraw 並設為 Details 檢視
        this.OwnerDraw = true;
        this.View = View.Details;
    }

    protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
    {
        e.DrawDefault = true; // 標題列維持預設繪製
        base.OnDrawColumnHeader(e);
    }

    protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
    {
        // 非目標欄位 → 預設繪製
        if (e.ColumnIndex != ProgressColumnIndex)
        {
            e.DrawDefault = true;
            base.OnDrawSubItem(e);
            return;
        }

        // 目標欄位:嘗試解析數值
        string text = e.Item.SubItems[e.ColumnIndex].Text;
        if (IsNumeric(text))
        {
            float percent = float.Parse(text);
            if (percent >= 1f) percent /= 100f; // 支援 0~100 或 0~1
            DrawProgressBar(e.Graphics, e.Bounds, percent);
        }
        else
        {
            e.DrawDefault = true;
            base.OnDrawSubItem(e);
        }
    }

    // 簡易數值判斷(含小數點)
    private bool IsNumeric(string s)
    {
        foreach (char c in s)
            if (!"0123456789.".Contains(c)) return false;
        return true;
    }

    // 實際繪製進度條
    private void DrawProgressBar(Graphics g, Rectangle bounds, float percent)
    {
        if (bounds.Height <= 2 || bounds.Width <= 2) return;
        if (bounds.Top < 0 || bounds.Top > this.Height || 
            bounds.Left < this.Left || bounds.Left > this.Width) return;

        // 進度填充區
        int fillWidth = (int)(bounds.Width * percent);
        Rectangle fillRect = new Rectangle(bounds.Left + 1, bounds.Top + 1, 
                                           Math.Max(0, fillWidth - 2), bounds.Height - 2);
        using (Brush b = new SolidBrush(ProgressColor))
            g.FillRectangle(b, fillRect);

        // 外框
        Rectangle borderRect = new Rectangle(bounds.Left + 1, bounds.Top + 1, 
                                             bounds.Width - 2, bounds.Height - 2);
        g.DrawRectangle(Pens.RoyalBlue, borderRect);

        // 百分比文字置中
        StringFormat sf = new StringFormat
        {
            Alignment = StringAlignment.Center,
            LineAlignment = StringAlignment.Center,
            Trimming = StringTrimming.EllipsisCharacter
        };
        using (Brush tb = new SolidBrush(ProgressTextColor))
            g.DrawString((percent * 100).ToString("F1") + "%", this.Font, tb, borderRect, sf);
    }

    private void InitializeComponent() { /* 設計工具自動產生 */ }
}

表單端使用範例

private void Form1_Load(object sender, EventArgs e)
{
    // 建立測試資料:四欄,第 2 欄 (Index=1) 為進度
    var item = new ListViewItem("5");
    item.SubItems.Add("0");   // 進度欄位,初始 0%
    item.SubItems.Add("3");
    item.SubItems.Add("100");
    listViewEx1.Items.Add(item);

    // 設定進度欄位與顏色
    listViewEx1.ProgressColumnIndex = 1;
    listViewEx1.ProgressColor = Color.YellowGreen;
    listViewEx1.ProgressTextColor = Color.Red;

    // 啟動 Timer 每 100ms 遞增進度
    timer1.Interval = 100;
    timer1.Start();
}

private void timer1_Tick(object sender, EventArgs e)
{
    var sub = listViewEx1.Items[0].SubItems[1];
    int val = int.Parse(sub.Text);
    if (val <= 100)
    {
        sub.Text = (val + 1).ToString();
        listViewEx1.Invalidate(); // 觸發重繪
    }
    else timer1.Stop();
}

關鍵細節補充

  • OwnerDraw 必須為 true,且 View = View.Details,否則 OnDrawSubItem 不會被呼叫。
  • ProgressColumnIndex 可在執行期動態切換,適合多欄位輪流顯示進度的情境。
  • 數值解析採寬鬆策略:0~100 視為百分比整數,0~1 視為小數,自動換算。
  • 繪製時以 Invalidate() 觸發重繪,而非直接呼叫 DrawSubItem,避免閃爍。
  • 若需支援多行、圖示、滾動列虛擬模式,請自行擴充 OnDrawItem、OnDrawColumnHeader 等事件。

執行效果

ListView 進度條示範

圖中第二欄顯示綠色進度條與紅色百分比文字,隨 Timer 從 0% 平滑遞增至 100%。

延伸應用建議

  • 搭配 BackgroundWorker 或 Task.Run 執行長時間作業,透過 Progress<int> 回報進度,UI 執行緒只負責更新 SubItem.Text 並 Invalidate()。
  • 將 ListViewEx 封裝為元件(.dll)並加入工具箱,即可在設計拖曳使用,提升複用性。
  • 若專案改用 WPF,建議改用 DataGrid + DataTemplate 實現更靈活的進度條樣式。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved