使用 Visual C# 建立平滑進度列

本文提供如何建立自定義 UserControl 以建立平滑的 Scrolling ProgressBar 控件的相關信息。

原始產品版本: Visual C#
原始 KB 編號: 323116

摘要

本文示範如何建立簡單的自定義UserControl,以建立平滑的Scrolling ProgressBar控件。

在舊版的 ProgressBar 控件中,例如隨 Microsoft Windows Common Controls ActiveX 控件所提供的版本,您可以在兩個不同的檢視中檢視進度。 若要控制這些檢視,您可以使用 Scrolling 屬性,其中包含標準和平滑設定。 平滑捲動會產生代表進度的純色區塊,而標準捲動會顯示分段,由一系列小型區塊或矩形組成。

Microsoft Visual C# 隨附的 ProgressBar 控件僅支持標準設定。

本文中的範例程式代碼說明如何建立支援下列屬性的控件:

  • 最小值:這個屬性會取得或設定有效值範圍的較低值以進行進度。 此屬性預設值為零 (0):您無法將此屬性設定為負值。
  • 最大值:此屬性會取得或設定進度有效值範圍的上限值。 這個屬性的預設值為 100。
  • 值:這個屬性會取得或設定目前進度層級。 值必須位於 Minimum 和 Maximum 屬性定義的範圍內。
  • ProgressBarColor:此屬性會取得或設定進度列的色彩。

建立自定義 ProgressBar 控件

  1. 請遵循下列步驟,在 Visual C# 中建立新的 Windows 控件連結庫專案:

    1. 啟動 Microsoft Visual Studio。

    2. [檔案] 功能表上,指向 [開新檔案] ,然後按一下 [專案]

    3. 在 [新增專案] 對話框中,按兩下 [項目類型] 下的 [Visual C#],然後按兩下 [範本] 底下的 [Windows Forms 控件連結庫]。

    4. 在 [ 名稱] 方塊中,輸入 SmoothProgressBar,然後按兩下 [ 確定]。

    5. [專案總管] 中,將默認類別模組從 UserControl1.cs 重新命名為 SmoothProgressBar.cs

    6. 在 UserControl 物件的 [ 屬性 ] 視窗中,將 Name 屬性從 UserControl1 變更為 SmoothProgressBar

  2. 此時,您通常會繼承自該控件的 類別,然後新增其他功能來擴充現有的控件。 不過,ProgressBar 類別是 密封的 ,無法繼承。 因此,您必須從頭開始建置 控件。

    在衍生自 UserControl 的類別中,將下列程式代碼新增至 SmoothProgressBar.cs 檔案。

    int min = 0;// Minimum value for progress range
    int max = 100;// Maximum value for progress range
    int val = 0;// Current progress
    Color BarColor = Color.Blue;// Color of progress meter
    
    protected override void OnResize(EventArgs e)
    {
        // Invalidate the control to get a repaint.
        this.Invalidate();
    }
    
    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        SolidBrush brush = new SolidBrush(BarColor);
        float percent = (float)(val - min) / (float)(max - min);
        Rectangle rect = this.ClientRectangle;
    
        // Calculate area for drawing the progress.
        rect.Width = (int)((float)rect.Width * percent);
    
        // Draw the progress meter.
        g.FillRectangle(brush, rect);
    
        // Draw a three-dimensional border around the control.
        Draw3DBorder(g);
    
        // Clean up.
        brush.Dispose();
        g.Dispose();
    }
    
    public int Minimum
    {
        get
        {
            return min;
        }
    
        set
        {
            // Prevent a negative value.
            if (value < 0)
            {
                value = 0;
            }
    
            // Make sure that the minimum value is never set higher than the maximum value.
            if (value > max)
            {
                max = value;
            }
    
            min = value;
    
            // Ensure value is still in range
            if (val < min)
            {
                val = min;
            }
    
            // Invalidate the control to get a repaint.
            this.Invalidate();
        }
    }
    
    public int Maximum
    {
        get
        {
            return max;
        }
    
        set
        {
            // Make sure that the maximum value is never set lower than the minimum value.
            if (value < min)
            {
                min = value;
            }
    
            max = value;
    
            // Make sure that value is still in range.
            if (val > max)
            {
                val = max;
            }
    
            // Invalidate the control to get a repaint.
            this.Invalidate();
        }
    }
    
    public int Value
    {
        get
        {
            return val;
        }
    
        set
        {
            int oldValue = val;
    
            // Make sure that the value does not stray outside the valid range.
            if (value < min)
            {
                val = min;
            }
            else if (value > max)
            {
                val = max;
            }
            else
            {
                val = value;
            }
    
            // Invalidate only the changed area.
            float percent;
    
            Rectangle newValueRect = this.ClientRectangle;
            Rectangle oldValueRect = this.ClientRectangle;
    
            // Use a new value to calculate the rectangle for progress.
            percent = (float)(val - min) / (float)(max - min);
            newValueRect.Width = (int)((float)newValueRect.Width * percent);
    
            // Use an old value to calculate the rectangle for progress.
            percent = (float)(oldValue - min) / (float)(max - min);
            oldValueRect.Width = (int)((float)oldValueRect.Width * percent);
    
            Rectangle updateRect = new Rectangle();
    
            // Find only the part of the screen that must be updated.
            if (newValueRect.Width > oldValueRect.Width)
            {
                updateRect.X = oldValueRect.Size.Width;
                updateRect.Width = newValueRect.Width - oldValueRect.Width;
            }
            else
            {
                updateRect.X = newValueRect.Size.Width;
                updateRect.Width = oldValueRect.Width - newValueRect.Width;
            }
    
            updateRect.Height = this.Height;
    
            // Invalidate the intersection region only.
            this.Invalidate(updateRect);
        }
    }
    
    public Color ProgressBarColor
    {
        get
        {
            return BarColor;
        }
    
        set
        {
            BarColor = value;
    
            // Invalidate the control to get a repaint.
            this.Invalidate();
        }
    }
    
    private void Draw3DBorder(Graphics g)
    {
        int PenWidth = (int)Pens.White.Width;
    
        g.DrawLine(Pens.DarkGray,
        new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
        new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top));
        g.DrawLine(Pens.DarkGray,
        new Point(this.ClientRectangle.Left, this.ClientRectangle.Top),
        new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth));
        g.DrawLine(Pens.White,
        new Point(this.ClientRectangle.Left, this.ClientRectangle.Height - PenWidth),
        new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
        g.DrawLine(Pens.White,
        new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Top),
        new Point(this.ClientRectangle.Width - PenWidth, this.ClientRectangle.Height - PenWidth));
    }
    
  3. 在 [ 建置] 功能表上,按兩下 [建置方案 ] 來編譯專案。

建立範例用戶端應用程式

  1. [檔案] 功能表上,指向 [開新檔案] ,然後按一下 [專案]

  2. 在 [新增專案] 對話框中,按兩下 [項目類型] 下的 [Visual C#],按兩下 [範本] 下的 [Windows Forms 應用程式],然後按兩下 [確定]。

  3. 請遵循下列步驟,將 SmoothProgressBar 控件的兩個實例新增至窗體:

    1. 在 [工具] 功能表中按一下 [選擇工具箱項目]

    2. 按兩下 [.NET Framework 元件] 索引標籤

    3. 按兩下 [瀏覽],然後找出您在 [建立自定義 ProgressBar 控件] 區段中建立SmoothProgressBar.dll檔案。

    4. 按一下 [確定]。

      注意

      SmoothProgressBar 控件會新增至工具箱。

    5. 將 SmoothProgressBar 控制件的兩個實例從工具箱拖曳到 Windows 應用程式專案的預設表單。

  4. 將定時器控件從工具箱拖曳至表單。

  5. 將下列程式代碼新增至 Tick Timer 控制項的事件:

    if (this.smoothProgressBar1.Value > 0)
    {
        this.smoothProgressBar1.Value--;
        this.smoothProgressBar2.Value++;
    }
    else
    {
        this.timer1.Enabled = false;
    }
    
  6. 將按鈕控件從工具箱拖曳至表單。

  7. 將下列程式代碼新增至 Click Button 控制的事件:

    this.smoothProgressBar1.Value = 100;
    this.smoothProgressBar2.Value = 0;
    
    this.timer1.Interval = 1;
    this.timer1.Enabled = true;
    
  8. 在 [ 偵錯] 功能表上,單擊 [ 開始 ] 以執行範例專案。

  9. 按一下 按鈕。

    注意

    這兩個進度指標會顯示文字 進度。 其中一個進度指標會以遞增的方式顯示進度,另一個進度指示器則會以遞減或倒數的方式顯示進度。