Anda di halaman 1dari 9

CmodetectarlateclapulsadaenunaceldadelcontrolDataGridView

PorEnriqueMartnezMontejo
[MicrosoftMostValuableProfessionalVisualBasic]
ltimarevisin:05/09/2007

EsteesunodelostemasestrelladelgrupodenoticiasenespaoldeVisualBasic.net,ysurazn
de ser tiene, porque en principio, todos creemos que mediante los clsicos eventos KeyDown,
KeyPress y KeyUp del control DataGridView, podemos tener un cierto control sobre lo que se
escribe en sus celdas. Pero cuando observamos que los eventos KeyDown y KeyUp slo
responden a un cierto tipo de teclas que son obvias (modificadoras, de desplazamiento, de
funcin,escape,intro,etc.),yqueningunodelostreseventossedesencadenaalpulsarlasteclas
correspondientes a letras, nmeros o smbolos, nos entra la desesperacin y un tanto de
desilusin.
Esciertoqueexistenotrasformasdecontrolardeunamanerageneral,lapulsacindelasteclas
queseefectanenelcontrolDataGridView.Porejemplo,podemosutilizarlostreseventosde
tecladodelformularioquecontienealcontrolDataGridView,opodemostambinreeemplazarla
funcinProcessCmdKey.PeromientraslosprimerosrequierenquelapropiedadKeyPreviewdel
formulariotengaelvalorTrue(paraquesedesencadenenloseventosdelformularioantesque
losmismoseventoscorrespondientesaloscontrolesincluidosenaquel),elreemplazarlafuncin
ProcessCmdKeyrequiere trabajar conmensajes de Windowse identificadores de ventanas (los
famososvaloreshWndoHandleddelaAPIdeWindows).
Aparte,tantoloseventosdelformulario,comolafuncinProcessCmdKey,sedesencadenaran,
no slo para los eventos de teclado del control DataGridView, sino para todos los eventos de
tecladodelosrestantescontrolesexistentesenelformulario,conlocualtendramosqueestar
comprobandoqucontroltieneelfoco,oelidentificadordeventana(hWnd)delcontrolqueha
provocado el evento. En mi opinin personal, hay otra solucin ms eficaz, que es tratar por
todos los medios que los propios eventos de teclado del control DataGridView, sobre todo el
eventoKeyPress,respondanalaspulsacionesdelasteclaspresionadas.Peroantesdeentraren
detallesobreloseventosdeteclado,vamosaconocerunpocomssobreloqueseescondepor
dentrodelcontrolDataGridView,quenoes,nimsnimenos,queunaseriedecontrolesquelos
programadoresdeVisualBasicsuelenconocerbastantebien.

LaclaseDataGridViewCell
EstaclaserepresentaunaceldaindividualexistenteenuncontrolDataGridView,quepodemos
referenciar fcilmente efectuando una simple consulta a la propiedad CurrentCell del control
DataGridView:
'Referenciamoslaceldaactual
'
DimdgvCellAsDataGridViewCell=Me.DataGridView1.CurrentCell

Deestamanerayaestamosencondicionesdeobtenerelvalordelasrestantespropiedadesdela
celda,comoelndicedelacolumna(ColumnIndex),elndicedelafila(RowIndex),oelvalordela

celda(Value).Perotambinpodemosconocerigualmente,eltipodecontroldeedicinquese
alojaenlaceldamediantelapropiedadEditTypedelcontrolDataGridView,quedependiendodel
tipo asignado a la columna, en principio puede corresponderse con alguna de las siguientes
clases:

Tiposdecolumnas

DataGridViewButtonColumn
DataGridViewCheckBoxColumn
DataGridViewComboBoxColumn
DataGridViewImageColumn
DataGridViewLinkColumn
DataGridViewTextBoxColumn

Tiposdeobjetosexistentesenlas
celdas
DataGridViewButtonCell
DataGridViewCheckBoxCell
DataGridViewComboBoxCell
DataGridViewImageCell
DataGridViewLinkCell
DataGridViewTextBoxCell

Parece ser que el nombre de cada clase denota bien el tipo de control que representan las
columnasyceldasdelcontrolDataGridView.
Cuando referenciamos una celda cualquiera del control DataGridView, automticamente
obtendremos el tipo de control alojado en ella, que se corresponder con el tipo de control
asignado a la columna a la que pertenece la celda. Continuando con el ejemplo anterior, si la
celdaactualseencuentraenunacolumnatipoDataGridViewCheckBoxColumn,lavariableobjeto
dgvCell referenciar a un objeto DataGridViewCheckBoxCell, y si la columna es del tipo
DataGridViewTextBoxColumn,eltipodeobjetodelaceldaserDataGridViewTextBoxCell.

LaclaseDataGridViewTextBoxCell
EstaclaseeslaencargadademostrartextomodificableenunaceldadelcontrolDataGridView,y
es la clase que por defecto tendrn todas las celdas existententes en dicho control, salvo que
expresamentelehayamosasignadoalacolumnaotrotipodeclaseDataGridViewXXXColumnde
lasmencionadasenelapartadoanterior,encuyocaso,lasceldasdeesacolumnaserndeltipo
deobjetoespecializado.
LaclaseDataGridViewTextBoxCellheredadirectamentedelaclasebaseDataGridViewCell,dela
quetomalainmensamayoradesuspropiedadesymtodos.
SinuestraintencinesreferenciarelobjetoDataGridViewTextBoxCellalojadoenlaceldaactual
delcontrolDataGridView,ejecutaramosalgoparecidoalosiguiente:
'ReferenciamoselcontrolDataGridViewTextBoxCellactual
'
DimtextBoxCellAsDataGridViewTextBoxCell=_
TryCast(Me.DataGridView1.CurrentCell,DataGridViewTextBoxCell)

Laimportanciadeestaclaseradicaenquelaceldaactualmenteseleccionada,alojaasuvezun
controldelaclaseDataGridViewTextBoxEditingControl,queeselcontrolquenospermiteeditar
el valor de la celda, siempre y cuando el valor de la propiedad ReadOnly del control
DataGridViewTextBoxCellseaFalse.

ElcontrolDataGridViewTextBoxEditingControl
Por fin hemos llegado al objeto ms recndito de la celda; al objeto
DataGridViewTextBoxEditingControlalojadoenelobjetoDataGridViewTextBoxCellexistenteasu
vez en el objeto DataGridViewCell, representado ste por la celda actual del control
DataGridView.
Desdeluego,nomeextraaquecontantosnombresparecidos,ydegranlongitud,msdeuno
sehagaunpequeolo.Perocuandosehayanpeleadounpardevecesconlasceldasdelcontrol
DataGridView,lesaseguroquevernlascosasdeotramanera.
Como bien nos d a entender el nombre del control DataGridViewTextBoxEditingControl, ste
heredadirectamentedelclsicocontroldeedicindeVisualBasic,elcontrolTextBox,portanto,
implementa todas las propiedades, mtodos y eventos de ste ltimo control, permitindonos
editarelcontenidodelacelda.
CuandounaceldacualquieradelcontrolDataGridViewpasaamododeedicin,sedesencadena
el evento EditingControlShowing, donde el segundo parmetro de su firma es un objeto de la
claseDataGridViewEditingControlShowingEventArgs(otronombremslargoanparaaadirala
lista). Esta clase dispone nicamente de dos propiedades pblicas: CellStyle (un objeto
DataGridViewCellStyle que referencia a la celda editada), y Control (que es el control
proporcionadoparaeditarelvalordelacelda).SerdelapropiedadControldondeobtendremos
elescndidocontrolDataGridViewTextBoxEditingControl,talycomosemuestraenelsiguiente
ejemplo:
PrivateSubDataGridView1_EditingControlShowing(_
ByValsenderAsObject,_
ByValeAsDataGridViewEditingControlShowingEventArgs)_
HandlesDataGridView1.EditingControlShowing
'ReferenciamoselcontrolTextBoxsubyacenteenlaceldaactual.
'
DimcellTextBoxAsDataGridViewTextBoxEditingControl=_
TryCast(e.Control,DataGridViewTextBoxEditingControl)
'Obtenemoselvaloractualdelacelda.
'
MessageBox.Show(cellTextBox.Text)
'Obtenemoselestilodelaceldaactual
'
DimstyleAsDataGridViewCellStyle=e.CellStyle
'Mientrasseeditalacelda,aumentaremoslafuente
'yrellenaremoselcolordefondodelaceldaactual.
'
Withstyle
.Font=NewFont(style.Font.FontFamily,10,FontStyle.Bold)

.BackColor=Color.Beige
EndWith
EndSub

Elresultadoserelquesemuestraenlaimagen,dondeseobservaquelaceldacambiaaotro
colordefondoyseaumentaeltamaodelafuente,mientrasseesteditando.

UnavezquehemossidocapacesdereferenciarelobjetoderivadodelaclaseTextBoxexistente
en una celda, por qu no vamos a ser capaces de controlar las pulsaciones de teclas que se
efectan en el mismo, si en definitiva se trata de un simple control TextBox? La solucin se
encuentraen instalar los correspondientes controladores para los tres eventos del teclado del
controlTextBox:KeyDown,KeyPressyKeyUp.
En el ejemplo anterior, la variable cellTextBox est declarada a nivel del propio procedimiento
que la contiene, por lo su mbito es local. Es cierto que en el mismo procedimiento podemos
instalarloscorrespondientescontroladoresdeeventomediantelainstruccinAddHandler,pero
cadavezqueseediteunacelda,seestarinstaladouncontrolador,ysiseeditan20.000celdas,
seinstalarn20.000controladores,quedesencadenarn20.000eventos,queenelcasodeestar
instalados para los tres eventos de teclado, producirn 60.000 eventos de teclado. Para evitar
queseinstaleuncontroladorcadavezqueseeditaunacelda,habraqueeliminarelcontrolador
con la instruccin RemoveHandler, por ejemplo, en el evento CellEndEdit del control
DataGridView,queseproducecuandofinalicelaedicindelacelda.
Pero, claro! Esto ltimo tiene un gran inconveniente, porque si eliminamos el controlador de
evento en otro procedimiento distinto (CellEndEdit) a aquel donde se ha instalado
(EditingControlShowing),necesitaremosunavariableobjetoconunmbitosuperiorallocalpara
poder eliminar el controlador de evento. La solucin pasa por declarar a nivel del propio
formulario que contiene el control DataGridView, una variable objeto que ser la que
sucesivamente estar referenciando al control DataGridViewTextBoxEditingControl de la celda
que actualmente se encuentre en modo de edicin, y declararemos la variable objeto con la
palabraclaveWithEvents,paranotenerqueaadiryeliminar manualmente los controladores
paralostreseventosdeteclado,talycomomuestroacontinuacin:
PrivateWithEventscellTextBoxAsDataGridViewTextBoxEditingControl
PrivateSubcellTextBox_KeyDown(_

ByValsenderAsObject,_

ByVal

As

System.Windows.Forms.KeyEventArgs)

Handles

cellTextBox.KeyDown
EndSub
PrivateSubcellTextBox_KeyPress(_
ByValsenderAsObject,_

ByVal e As

System.Windows.Forms.KeyPressEventArgs)

Handles

cellTextBox.KeyPress
EndSub
PrivateSubcellTextBox_KeyUp(_
ByValsenderAsObject,_
ByValeAsSystem.Windows.Forms.KeyEventArgs)HandlescellTextBox.KeyUp
EndSub
PrivateSubDataGridView1_EditingControlShowing(_
ByValsenderAsObject,_
ByValeAsDataGridViewEditingControlShowingEventArgs)_
HandlesDataGridView1.EditingControlShowing
'Esteeventoseproducircuandolaceldapasaamododeedicin.
'ReferenciamoselcontrolDataGridViewTextBoxEditingControlactual.
'
cellTextBox=TryCast(e.Control,DataGridViewTextBoxEditingControl)
'Obtenemoselestilodelaceldaactual
'
DimstyleAsDataGridViewCellStyle=e.CellStyle
'Mientrasseeditalacelda,aumentaremoslafuente
'yrellenaremoselcolordefondodelaceldaactual.
'
Withstyle
.Font=NewFont(style.Font.FontFamily,10,FontStyle.Bold)
.BackColor=Color.Beige
EndWith
EndSub

CmodeclararunobjetoDataGridViewTextBoxEditingControlparaserutilizadoporloseventos
delteclado
Bueno. Ya est en condiciones de detectar la tecla pulsada en cualquier celda del control
DataGridViewqueseencuentreactualmenteenmododeedicin.
Los eventos correspondientes al control de edicin de la celda, unidos a los tres eventos del
tecladodelpropiocontrolDataGridView,enteoranosdebe de dar toda la flexibilidad posible
paradetectarlasteclasqueelusuariohapresionado.
A continuacin paso a exponer algunos ejemplos para trabajar con los eventos del teclado
descritos,dependiendodeciertasaccionesenconcreto.Contotalseguridad,enlaRedderedes
existirnmilesdeejemplosmejoresquelosqueencontraraqu,peroloqueslopretendoes
mostrarlesimplementeunamaneramsderealizarunaoperacinconcreta,quenoquieredecir
quesealamejor.

Permitirslonmeros,elcarcterseparadordecimal,yelcarcternegativo,en
lasceldasdeuncontrolDataGridView.
Si en nuestro control DataGridView tenemos una columna donde nos interesara que slo se
introdujerandatosnumricos(enterosodecimales),controlaramoslapulsacindeteclasenel
eventoKeyPressdelobjetoDataGridViewTextBoxEditingControldeclaradoaniveldelformulario.
Porsupuestoqueelejemplotambinserviraparapermitirloscitadoscaracteresenunsimple
controlTextBox,quecomosehaexplicadoenelartculo,eselcontrolqueexisteenlasceldasde
uncontrolDataGridView.
PrivateSubcellTextBox_KeyPress(_
ByValsenderAsObject,_

ByVal e As

System.Windows.Forms.KeyPressEventArgs)

cellTextBox.KeyPress
'ReferenciamoselcontrolTextBoxsubyacente.
'
DimtbAsTextBox=TryCast(sender,TextBox)
'Silaconversinhafallado,abandonamoselprocedimiento.
'
If(tbIsNothing)Then
e.Handled=True
Return
EndIf
DimisDecimal,isSign,isValidCharAsBoolean
DimdecimalSeparatorAsString=Nothing
SelectCasee.KeyChar

Handles

Case"."c,","c
'Obtenemoselcarcterseparadordecimalexistente
'actualmenteenlaconfiguracinregionaldeWindows.
'
decimalSeparator=_
Threading.Thread.CurrentThread._
CurrentCulture.NumberFormat.NumberDecimalSeparator
'Hacemosqueelcarctertecleadocoincidaconel
'carcterseparadorexistententeenlaconfiguracin
'regional.
'
e.KeyChar=decimalSeparator.Chars(0)
'Sielprimercarcterquesetecleaeselseparadordecimal,
'osibien,existeunsignoenelprimercarcter,envola
'combinacin'0,'.
'
If (((tb.TextLength = 0) OrElse (tb.SelectionLength =
tb.TextLength))OrElse_
((tb.TextLength=1)AndAlso((tb.Text.Contains(""))OrElse
_
(Text.Contains("+")))))Then
'NOTA:Envolacombinacin"0,"medianteelmtodoSend,
'paraqueenelcdigoclientesedesencadenenlos
'eventosdeteclado.
'
SendKeys.Send("{0}")
SendKeys.Send("{"&decimalSeparator&"}")
e.Handled=True
Return
EndIf
'Esuncarctervlido.
'
isDecimal=True
isValidChar=True
Case""c,"+"c'Signosnegativoypositivo
'Esuncarctervlido.
'
isMinus=True

isValidChar=True
CaseElse
'Sloseadmitirnnmerosylatecladeretroceso.
'
DimisDigitAsBoolean=Char.IsDigit(e.KeyChar)
DimisControlAsBoolean=Char.IsControl(e.KeyChar)
If((isDigit)OrElse(isControl))Then
isValidChar=True
Else
e.Handled=True
Return
EndIf
EndSelect
'Siesuncarctervlido,yeltextodelcontrol
'seencuentratotalmenteseleccionado,elimino
'elvaloractualdelcontrol.
'
If((isValidChar)And(tb.SelectionLength=tb.TextLength))Then
tb.Text=String.Empty
EndIf
If(isSign)Then
'Admitimosloscaracterespositivoynegativo,siempreycuando
'seaelprimercarcterdeltexto,ynoexistayaningnotro
'signoescritoenelcontrol.
'
If((tb.SelectionStart<>0)OrElse_
(tb.Text.IndexOf("")>=0)OrElse_
(tb.Text.IndexOf("+")>=0))Then
e.Handled=True
Return
EndIf
EndIf
If(isDecimal)Then
'Sienelcontrolhayyaescritounseparadordecimal,
'deshechamosinsertarotroseparadorms.
'

If(tb.Text.IndexOf(decimalSeparator)>=0)Then
e.Handled=True
Return
EndIf
EndIf
EndSub

Comobienpodrcomprobar,elejemplotieneencuentaelcarcterseparadordecimalexistente
en la configuracin regional del usuario, que en algunos casos ser el punto (.), y en otros la
coma(,).
Asimismo, tambin tiene en cuenta si se desea introducir un numro negativo, que slo se
permitirsielsignomenos()eselprimercarcterexistenteenlaceldaoenelcontrolTextBox.

Otrosenlacesdeinters:
ndicedelacoleccindeejemplosdelasclasesdelmarcodetrabajode.NET
EnriqueMartnezMontejo2007
NOTA: La informacin contenida en este artculo, as como el cdigo fuente incluido en el mismo, se proporciona
COMOEST, sin garantas de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poneren
prctica,utilizaroejecutarloexplicado,recomendadoosugeridoenelpresenteartculo.
NOTE:Theinformationcontainedinthisarticleandsourcecodeincludedtherein,isprovidedASISwithoutwarrantyof
anykind,andconfersnorights.Youassumeanyrisktoimplement,useorrunitexplained,recommendedorsuggested
inthisarticle.

Anda mungkin juga menyukai