DataGridViewColumn y DataGridViewCell. Creación de columnas personalizadas para el control DataGridView (1)

La creación para el control DataGridView, de una columna cuyas celdas contengan botones, los cuales realicen una determinada acción al ser pulsados, es una tarea muy sencilla, tal y como ya explicamos en un artículo anterior de este blog, donde la clase DataGridViewButtonColumn nos proveía de los botones con toda la funcionalidad típica ya implementada.

Pero supongamos que nuestro DataGridView necesita una columna de botones con un mayor grado de personalización, donde por ejemplo, dibujemos una imagen dentro del botón, la cual cambie su tamaño cuando el cursor del ratón entre en su superficie.

Este comportamiento personalizado y otros muchos pueden ser logrados partiendo de cero si heredamos de las clases DataGridViewColumn y DataGridViewCell, como veremos a lo largo de las diferentes entregas que componen este artículo.

 

El proyecto base del ejemplo

En esta primera parte comenzaremos creando, desde Visual Studio 2008, un nuevo proyecto de tipo Windows Forms Application con el nombre DGVColumnaCeldasBotonPersonalizado, agregando al diseñador del formulario un DataGridView y varios controles adicionales, hasta conseguir el aspecto de la siguiente imagen.

 

En el manipulador del evento Load de este formulario añadiremos el siguiente bloque de código, que rellenará el DataGridView con un conjunto de registros de la tabla DimProduct, perteneciente a la base de datos AdventureWorksDW.

//....
using System.Data.SqlClient;
//....
private void Form1_Load(object sender, EventArgs e)
{
    SqlConnection cnConexion = new SqlConnection();
    cnConexion.ConnectionString = "Data Source=localhost;" +
        "Initial Catalog=AdventureWorksDW;" +
        "Integrated Security=True";

    string sSQL = "SELECT ProductKey, SpanishProductName, ListPrice " +
        "FROM DimProduct WHERE ListPrice IS NOT NULL";

    SqlCommand cmdComando = new SqlCommand(sSQL, cnConexion);
    SqlDataAdapter daAdaptador = new SqlDataAdapter(cmdComando);
    DataSet dsDatos = new DataSet();
    daAdaptador.Fill(dsDatos, "DimProduct");

    this.dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
    this.dataGridView1.DataSource = dsDatos;
    this.dataGridView1.DataMember = "DimProduct";
}

De esta forma, el control presentará el siguiente aspecto en tiempo de ejecución. 

 

 

Comenzando la creación de la columna personalizada

A continuación añadiremos al proyecto dos nuevas clases: la primera, DGVColumnaBoton, heredará de DataGridViewColumn, y constituirá la base para las celdas que conformarán su contenido; la segunda, DGVCeldaBoton, heredará de DataGridViewCell, y en ella crearemos los botones que constituirán el contenido de la columna, así como la implementación de la lógica para su comportamiento visual.

using System.Windows.Forms;
using System.Drawing;
using System.Windows.Forms.VisualStyles;
//....
//----------------------------------------
class DGVColumnaBoton : DataGridViewColumn
{
    // inicializar una nueva instancia de esta clase
    // pasando como parámetro una plantilla de celda, es decir, 
    // una instancia de la clase DataGridViewCell o derivada
    public DGVColumnaBoton()
        : base(new DGVCeldaBoton())
    {
    }
    //....
}

//------------------------------------
class DGVCeldaBoton : DataGridViewCell
{
    //....
}

 

DGVColumnaBoton. La clase para la construcción de columnas

Comenzando por la clase DGVColumnaBoton, el código que tenemos que escribir para la misma es muy sencillo, ya que consistirá en dos propiedades, que contendrán la información de la ruta en la que está el archivo de imagen para el botón, y una instancia de la propia imagen.

class DGVColumnaBoton : DataGridViewColumn
{
    private string sImagen;
    private Bitmap bmpImagen;

    // inicializar una nueva instancia de esta clase
    // pasando como parámetro una plantilla de celda, es decir, 
    // una instancia de la clase DataGridViewCell o derivada
    public DGVColumnaBoton()
        : base(new DGVCeldaBoton())
    {
    }

    public string Imagen
    {
        get
        {
            return sImagen;
        }

        set
        {
            sImagen = value;
            bmpImagen = new Bitmap(value);
            this.Width = bmpImagen.Size.Width;
        }
    }

    internal Bitmap ImagenBitmap
    {
        get
        {
            return bmpImagen;
        }
    }
}

 

DGVCeldaBoton. La clase para la construcción de celdas

La clase DGVCeldaBoton sin embargo va a darnos más trabajo, lo cual resulta totalmente comprensible, puesto que, como ya hemos apuntado anteriormente, será donde tendremos que codificar todo el comportamiento visual que queramos proporcionar a los botones alojados en las celdas. Empezaremos reemplazando la propiedad FormattedValueType, que se emplea para establecer el tipo de los datos formateados que se visualizan en la celda. En nuestro caso devolveremos un tipo object.

class DGVCeldaBoton : DataGridViewCell
{
    public override Type FormattedValueType
    {
        get
        {
            return typeof(object);
        }
    }
    //....
}

En este momento ya podríamos crear una instancia de nuestra nueva clase personalizada de columna, y añadirla al DataGridView del formulario de ejemplo. Observe el lector, cómo establecemos el tamaño de la columna personalizada mediante la asignación de las propiedades DataGridView.RowTemplate.Height y DGVColumnaBoton.Width.

private void Form1_Load(object sender, EventArgs e)
{
    //....
    this.dataGridView1.RowTemplate.Height = 70;

    this.dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
    this.dataGridView1.DataSource = dsDatos;
    this.dataGridView1.DataMember = "DimProduct";


    DGVColumnaBoton colBotones = new DGVColumnaBoton();
    colBotones.Name = "colBotones";
    colBotones.HeaderText = "Descuento";
    colBotones.Imagen = System.Environment.CurrentDirectory + @"BotonIr.jpg";
    colBotones.Width = 70;

    this.dataGridView1.Columns.Add(colBotones);
}

No obstante, el resultado obtenido no será el esperado, ya que como vemos en la siguiente imagen, el área del DataGridView donde debería aparecer nuestra nueva columna se encuentra vacía.

 

Concluye aquí la primera parte de este artículo, en donde hemos sentado las bases para la construcción de una columna personalizada para el control DataGrid. En la siguiente entrega explicaremos los pasos relacionados con el dibujo de las celdas contenidas en la columna, así como los diferentes estados visuales que pueden tomar los botones contenidos en las celdas al interaccionar el usuario. En los enlaces C# y VB el lector tiene disponible el proyecto con el código fuente completo del ejemplo.

Un saludo.

6 Comentarios

  1. anonymous

    Buenas, quiero darte las gracias por las aportaciones que haces en tus articulos, te sigo hace poco pero he aprendido mucho gracias a ti sobre todo con los articulos de RIA y WinForms.

    Pues eso 🙂

    Saludos!

  2. anonymous

    En la primera entrega de este artículo, el desarrollo de nuestra columna quedó pendiente

  3. lmblanco

    Hola Xose

    Pues te agradezco muchísimo tus ánimos y me alegro que los artículos del blog te estén resultando de utilidad 8-), espero que los próximos también te resulten de ayuda.

    Un saludo.
    Luismi

  4. anonymous

    Hola, como puedo agregar un combobox a un datagrid para poder utilizar el autocompletemode, y que me permita escribir un texto que no se encuentre en los items?

  5. manueljrv

    Hola Luis. he intentado plasmar tu ejemplo , en tu ejemplo si le agregas una propiedad a la clase DGVColumnaBoton por ejemplo llamada ruta de tipo string y agregas esta columna por diseño y ya no por codigo , la pregunta es por si a la propiedad ruta le das como valor «C:BotonIr.jpg» y cierras la ventada de propiead del datagridview este valor «C:BotonIr.jpg» no se graba , lo he intentado y no logro que el valor de esta propiedad se grave.

    gracias por tu apoyo.

Deja un comentario

Tema creado por Anders Norén