Controles comunes personalizados CSharp

La plataforma .NET desde su versión 1.1 ofrece la facilidad de poder generar controles comunes personalizados para satisfacer las necesidades de los desarrolladores que necesitan agregar, quitar o modificar el comportamiento, la funcionalidad y el diseño de cualquier control común (System.Windows.Forms.Control).

Clase ControlEditar

En la clase Control (System.Windows.Forms.Control) se encuentran contenidos los siguientes controles comunes perzonalizables.

  • AxHost
  • ButtonBase
  • DataGrid
  • DataGridView
  • DateTimePicker
  • GroupBox
  • Label
  • ListControl
  • ListView
  • MdiClient
  • MonthCalendar
  • PictureBox
  • PrintPreviewControl
  • ProgressBar
  • ScrollableControl
  • ScrollBar
  • Splitter
  • StatusBar
  • TabControl
  • TextBoxBase
  • ToolBar
  • TrackBar
  • TreeView
  • WebBrowserBase

EjemploEditar

Suponiendo que se necesita hacer una representación dinámica de un gráfico, para el cual es necesario que los vértices y aristas se comporten como botones para que se pueda hacer click sobre ellos; es necesario personalizar un botón (System.Windows.Forms.Button) de la siguiente manera:

VérticeEditar

Se representa como un circulo con un identificador alfanumérico interno; plano, sin relleno (transparente), sin cambios al hacer click sobre el.

Definición de la claseEditar

class Vertice : Control
{
    private string identificador;

    public string Identificador  { set { this.identificador  = value; } get { return this.identificador;  } }
   
    public Vertice(string identificador)
    {
        //
    }
}

ConstructorEditar

public Vertice(string identificador)
{
    this.identificador = identificador;
    //Propios del control
    this.Enabled = true;                //Habilita el control
    base.CreateControl();               //Forza a crear el control
}

Eventos personalizadosEditar

protected override void OnCreateControl()
{
    using(var zona = new GraphicsPath())
    {
        zona.AddEllipse(new Rectangle(0, 0, 25, 25);
        this.Region = new Region(zona); //La región del botón ahora es un círculo
    }
    base.OnCreateControl();
}

protected override void OnPaint(PaintEventArgs pevent)
{
    Brush brushFuente;
    Rectangle cajaVertice;
    StringFormat formato;
    
    pevent.Graphics.SmoothingMode = System.Drawing.SmoothingMode.AntiAlias;
    pevent.Graphics.Clear();

    formato = new StringFormat();
    formato.Alignment = StringAlignment.Center;
    formato.LineAlignment = StringAlignment.Center;
    brushFuente = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
    cajaVertice = new System.Drawing.Rectangle(0, 0, 25, 25);
    pevent.Graphics.DrawEllipse(new System.Drawing.Pen(System.Drawing.Color.Black),
                                3, cajaVertice);
    pevent.Graphics.DrawString(this.Identificador,
                               new System.Drawing.Font("Arial", 12),
                               brushFuente, cajaVertice, formato);
}

AristaEditar

Se representa como una linea recta que une a 2 vértices en cualquier parte del área cliente; con relleno, sin cambios al hacer click sobre ella.

Definición de la claseEditar

class Arista : Control
{
    private Vertice origen;
    private Vertice destino;
	private Arista siguiente;

    public Vertice Origen    { set { this.origen    = value; } get { return this.origen;   } }
    public Vertice Destino   { set { this.destino   = value; } get { return this.destino;  } }
    public Arista  Siguiente { set { this.siguiente = value; } get { return this.siguiente;} }
    
    public Arista(Vertice origen, Vertice destino)
    {
        //
    }
}

ConstructorEditar

public Arista(Vertice origen, Vertice destino)
{
    this.origen    = origen;
    this.destino   = destino;
    this.siguiente = null;
    //Propios del control
    this.Enabled   = true;
    base.CreateControl();
}

Eventos personalizadosEditar

Hay que tener en cuenta que por definición en el método System.Drawing.Drawing2D.GraphicsPath.AddLine agrega una linea con grosor cero (sin volumen), ya que normalmente se espera que la región se forme a partir de una figura cerrada, por lo que es necesario especificar un ancho para que esta linea tome un grosor mayor a cero y con esto el nuevo botón sea visible en el área cliente al momento de dibujarlo.

protected override void OnCreateControl()
{
    using(var zona = new GraphicsPath())
    {
        zona.AddLine(this.origen.Location.X + 20,
                     this.origen.Location.Y + 20,
                     this.destino.Location.X + 20,
                     this.destino.Location.Y + 20);
        zona.Widen(new Pen(System.Drawing.Color.Black, 2)); //Default = Black, 0
        this.Region = new Region(zona);    //La región del botón ahora es una linea
    }                                      //con grosor de 2 unidades
    base.OnCreateControl();
}
protected override void OnPaint(PaintEventArgs pevent)
{
    superficie.SmoothingMode = SmoothingMode.AntiAlias;
    superficie.DrawLine(new Pen(System.Drawing.Color.Black, 2),
                        this.origen.Location.X + 20,
                        this.origen.Location.Y + 20,
                        this.destino.Location.X + 20,
                        this.destino.Location.Y + 20);
}

Enlaces externosEditar