En este artículo voy a mostrar cómo crear un nuevo tipo de columna para el
DataGridView para almacenar valores numéricos enteros, de forma que las celdas únicamente admitan la introducción de caracteres numéricos.
Creando la Clase IntegerGridColumn
Voy a crear un nuevo proyecto GridExtension del tipo Biblioteca de Clases.
Al proyecto le agregaré una referencia al ensamblado System.Windows.Forms de forma que tenga acceso a las clases del control DataGridView.
Dentro del proyecto voy a crear un nuevo archivo IntegerGridColumn.cs/IntegerGridColumn.vb en el que voy a definir dos clases. La clase IntegerGridColumn que hereda de DataGridViewColumn y la clase IntegerGridCell que hereda de DataGridViewTextBoxCell.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace GridExtension
{
public class IntegerGridColumn : DataGridViewColumn
{
}
public class IntegerGridCell : DataGridViewTextBoxCell
{
}
}
Imports System.Windows.Forms
Public Class IntegerGridColumn
Inherits DataGridViewColumn
End Class
Public Class IntegerGridCell
Inherits DataGridViewTextBoxCell
End Class
En la clase
IntegerGridCell voy a sobreescribir la propiedad
ValueType para especificar que el tipo de los valores de la celda es
Int32, y el método
InitializeEditingControl para añadir un controlador de evento al evento
KeyPress del control de edición de la celda.
El controlador de este evento (el método
IntegerGridCell_KeyPress) va a ser el responsable de controlar que los caracteres se correspondan con caracteres numéricos. En caso contrario establece la propiedad
Handled del objeto
KeyPressEventArgs a
true para anular el tratamiento de la tecla pulsada.
public class IntegerGridCell : DataGridViewTextBoxCell
{
public IntegerGridCell() : base() { }
public override Type ValueType
{
get { return typeof(Int32); }
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
Control ctl = DataGridView.EditingControl;
ctl.KeyPress += new KeyPressEventHandler(IntegerGridCell_KeyPress);
}
private void IntegerGridCell_KeyPress(object sender, KeyPressEventArgs e)
{
DataGridViewCell currentCell = ((IDataGridViewEditingControl)sender).EditingControlDataGridView.CurrentCell;
if (currentCell is IntegerGridCell)
e.Handled = !char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar);
}
}
Public Class IntegerGridCell
Inherits DataGridViewTextBoxCell
Public Sub New()
MyBase.New()
End Sub
Public Overrides ReadOnly Property ValueType As Type
Get
Return GetType(Int32)
End Get
End Property
Public Overrides Sub InitializeEditingControl(rowIndex As Integer, initialFormattedValue As Object, dataGridViewCellStyle As DataGridViewCellStyle)
MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)
Dim ctl As Control = DataGridView.EditingControl
AddHandler ctl.KeyPress, AddressOf IntegerGridCell_KeyPress
End Sub
Private Sub IntegerGridCell_KeyPress(sender As Object, e As KeyPressEventArgs)
Dim currentCell As DataGridViewCell = CType(sender, IDataGridViewEditingControl).EditingControlDataGridView.CurrentCell
If TypeOf currentCell Is IntegerGridCell Then
e.Handled = Not Char.IsControl(e.KeyChar) AndAlso Not Char.IsDigit(e.KeyChar)
End If
End Sub
End Class
En el constructor de la clase
IntegerGridColumn voy a llamar al constructor de
DataGridViewColumn pasándole una instancia de
IntegerGridCell como plantilla de celda. Voy a sobreescribir también la propiedad
CellTemplate para comprobar que la celda que se establece como plantilla es del tipo
IntegerGridCell.
public class IntegerGridColumn : DataGridViewColumn
{
public IntegerGridColumn() : base(new IntegerGridCell()) { }
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(IntegerGridCell)))
throw new InvalidCastException("Debe ser del tipo IntegerGridCell");
base.CellTemplate = value;
}
}
}
Public Class IntegerGridColumn
Inherits DataGridViewColumn
Public Sub New()
MyBase.New(New IntegerGridCell())
End Sub
Public Overrides Property CellTemplate As DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set(value As DataGridViewCell)
If value IsNot Nothing AndAlso _
Not value.GetType().IsAssignableFrom(GetType(IntegerGridCell)) Then
Throw New InvalidCastException("Debe ser del tipo IntegerGridCell")
End If
MyBase.CellTemplate = value
End Set
End Property
End Class
Con esto ya estaría creado el nuevo tipo de columna. Para probarlo voy a añadir a la solución un nuevo proyecto
GridTest del tipo Aplicación de Windows Forms.
Al proyecto
GridTest le he añadido una referencia al proyecto
GridExtension.
En el formulario que Visual Studio crea por defecto le he añadido un control
DataGridView al que le he agregado dos columnas: una columna
Texto del tipo
DataGridViewTextBoxColumn y una columna
Entero del tipo
IntegerGridColumn.
Ahora ya podemos arrancar la aplicación para comprobar el funcionamiento del nuevo tipo de columna.
El código completo de este artículo, tanto en C# como en Visual Basic, está disponible en:
Códigos de muestra - Ejemplos MSDN
Esto esta muy bueno, y si se pudiera hacer que la entrada de datos sea decimal, es decir como en un facturador que se entra el número 15000 y automáticamente acomoda el número a 15.000,00 ?
ResponderEliminarHola Rodolfo,
EliminarPara aceptar y formatear números decimales lo que haría es añadir un control de edición (seguramente con un MaskedTextBox) al estilo del ejemplo que tengo en el blog para crear columnas para editar fechas:
DataGridView. Columna con editor de fechas
A ver si saco un rato y monto un ejemplo.
Un saludo
He tardado un poco pero ya hay disponible un ejemplo de columna numérica que permite especificar el número de dígitos decimales:
EliminarColumna para números con decimales
Espero que sea de utilidad.
Gracias Asier, Voy a estar esperando tu ejemplo. Ojala sea con Net 2
ResponderEliminarHola Asier:
ResponderEliminarLo primero es darte las gracias por los ejemplos que tienes, ya que son realmente muy buenos.
También estaría interesado en ver un ejemplo donde una columna del datagridview solamente aceptase números con dos decimales.
Un Saludo.
No eres el primero que me lo pide. A ver si este fin de semana puedo preparar un ejemplo.
EliminarHe tardado un poco pero ya hay disponible un ejemplo de columna numérica que permite especificar el número de dígitos decimales:
EliminarColumna para números con decimales
Espero que sea de utilidad.
Es muy bueno tu ejemplo, yo tengo un problema, lo que necesito que aparesca un boton en la celda activa, para hacer una busqueda!
ResponderEliminarHoja Jorge.
ResponderEliminarÚltimamente ando con poco tiempo para preparar ejemplos, pero me lo apunto. A ver si puedo sacar un rato un día de estos.
Para hacerlo puedes fijarte en otros dos artículos del blog:
En Control TextBox con Botón muestro como crear un control TextBox que tenga un botón incorporado.
Una vez que tienes el control se trataría de crear un DataGridViewColumn que utilice como editor este control. Algo parecido a lo que muestro en el artículo DataGridView. Columna con editor de fechas, en el que creo una columna que utiliza el control DateTimePicker como editor.
Espero que te ayude.
Hola Doc, muy bueno blog, tengo una consulta después de crear la clase y agregarlo en la referencia no me sale el tipo de dato IntegerGridCell en la lista de tipos de datos al agregar o modificar un campo del DataGridView, yo estoy usando el VisualStudio Comunity 2015 crees que haya algún problema con esto? ojo que todo ha terminado ok con la clase, gracias
ResponderEliminarLo que te debería aparecer es el tipo IntegerGridColumn entre los tipos de columna a seleccionar cuando añades una nueva columna en el DataGridView. Si no te aparece prueba a recompilar la solución o a cerrar y volver a abrir el formulario para que se refresquen las referencias.
Eliminar