En vez de crear uno from scratch, mucho mejor extender el ProgressBar, añadirle nuevas propiedades y redefinir como repintarlo. Código fuente al final del artículo ;)
Entre los puntos fuertes de extender un control WinForm, esta el de redifinir los estilo con Control.SetStyle y sobreescribir el método OnPaint, dentro de este obtemenos el objeto Graphics con el que podemos pintar formas y textos. Mediante atributos configuramos los elementos que Visual Studio usará para mostrar sus propiedades:
Asi mediante VS2005 podemos configurar los nuevos elementos de nuestro ProgressBar, además de ocultar otros que no nos interesan como se puede ver con por ejemplo la propiedad Style.
Pintar en un formulario es relativemente fácil con la clase Graphics y sus utilidades, pero requiere algo de paciencia y "prueba-error" para ajustarlo adecuadamente. Me apunto en el TODO escribir sobre las nociones básicas de GDI+.
Y ahora... el código fuente:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
internal class resfinder { }
namespace CustomProgressBars
{
[ToolboxBitmap(typeof(resfinder), "FlatProgressBar.FlatProgressBar.bmp")]
public class FlatProgressBar : ProgressBar
{
private Pen _border;
private String _text;
private SolidBrush _brushForeColor;
private SolidBrush _brushBarColor;
[Browsable(true)]
[CategoryAttribute("FlatProgressBar"),
DescriptionAttribute("Color de la Barra")]
public Color BarColor
{
get { return _brushBarColor.Color; }
set { _brushBarColor.Color = value; }
}
[Browsable(true)]
[CategoryAttribute("FlatProgressBar"),
DescriptionAttribute("Color del Texto")]
public Color TextColor
{
get { return _brushForeColor.Color; }
set { _brushForeColor.Color = value; }
}
[Browsable(true)]
[CategoryAttribute("FlatProgressBar"),
DescriptionAttribute("Color del Borde")]
public Color BorderColor
{
get { return _border.Color; }
set { _border.Color = value; }
}
[Browsable(true)]
[CategoryAttribute("FlatProgressBar"),
DescriptionAttribute("Color del Borde")]
public Single BorderWidth
{
get { return _border.Width; }
set { _border.Width = value; }
}
[Browsable(true)]
[CategoryAttribute("FlatProgressBar"),
DescriptionAttribute("Color de Fondo")]
public new Color BackColor
{
get { return base.BackColor; }
set { base.BackColor = value; }
}
[Browsable(true)]
[CategoryAttribute("FlatProgressBar"),
DescriptionAttribute("Texto de la barra"),
DefaultValue("Text")]
public new String Text
{
get { return _text; }
set { _text = value; }
}
[Browsable(true)]
[CategoryAttribute("FlatProgressBar"),
DescriptionAttribute("Tipo de fuente del texto.")]
public new Font Font
{
get { return base.Font; }
set { base.Font = value; }
}
[Browsable(false)]
new public ProgressBarStyle Style
{
get { return ProgressBarStyle.Continuous; }
set { }
}
[Browsable(false)]
new public Int32 MarqueeAnimationSpeed
{
get { return 0; }
set { }
}
[Browsable(false)]
new public Color ForeColor
{
get { return TextColor; }
set { }
}
public FlatProgressBar()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor, true);
_border = new Pen(Brushes.Black);
_brushForeColor = new SolidBrush(Color.White);
_brushBarColor = new SolidBrush(Color.Gray);
base.Font = new Font("Tahoma", 10, FontStyle.Bold);
}
protected override void OnPaint(PaintEventArgs e)
{
// cuando mide cada paso
Single step = (Single)this.Width / this.Maximum;
// cuantos puntos es el progreso actual
Single progressInPoints = (this.Value * step);
progressInPoints = progressInPoints > 0 ? progressInPoints : 0;
// barra de progreso
e.Graphics.FillRectangle(_brushBarColor, 0, 0, progressInPoints, this.Height);
// texto con antialias
SmoothingMode bk = e.Graphics.SmoothingMode;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// escribo el texto
e.Graphics.DrawString(_text, Font, _brushForeColor,
new PointF(6, (this.Height - this.Font.Height) / 2));
string percent = ((this.Maximum / 100) * this.Value).ToString() + '%';
percent = percent.PadLeft(4, ' ');
// mido el porcentaje en puntos para saber
// donde ubicarlo
SizeF swidth = e.Graphics.MeasureString(percent, base.Font);
// escribo porcentaje
e.Graphics.DrawString(percent, base.Font, _brushForeColor,
new PointF((this.Width - _border.Width - swidth.Width - 1),
(this.Height - base.Font.Height) / 2));
// restauro el modo
e.Graphics.SmoothingMode = bk;
// dibujo el border si es mayor que 0
if (_border.Width >= 1)
e.Graphics.DrawRectangle(_border, 0, 0, this.Width - 1, this.Height - 1);
}
}
}