使用 Visual C# 创建平滑进度栏

本文介绍如何创建自定义 UserControl 以创建平滑滚动 ProgressBar 控件。

原始产品版本: Visual C#
原始 KB 数: 323116

总结

本文演示如何创建一个简单的自定义 UserControl 来创建平滑滚动的 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 窗体控件库”。

    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 窗体应用程序”,然后单击“确定”。

  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. 单击“”按钮。

    注意

    两个进度指示器显示文本 进度。 一个进度指示器以递增方式显示进度,另一个进度指示器以递减或倒计时方式显示进度。