** Henry ** ** 手记 ** ** ** ** - ** ** Datagrid ** ** 事件响应 ** ** ( ** ** 二 ** ** ) **
韩睿 ( 5/6/2003)
hi,大家好。对于windows form中的datagrid控件的使用,我已经写了不少文章了,但也不断地收到网友的意见,希望再多写一点。应朋友的要求,我会再针对几个问题写一些文章,希望能带给您一点启发,能够熟练地使用Datagrid,更主要是希望您能举一反三,将处理问题的方法应用到对其它控件的使用中去。
本文主要解决在 Datagrid 中任意点击一个格子,都会出现选中一行的需求。通过本文,您也会了解焦点与控件的关系。
这个问题看上去很简单,但是,如果您平时留心的话,每次点击单元格时,我们就会点击到一个格子的内部,而不会选中一行。想要选中一行,只能点击每行的行头。
有朋友会说,就还不简单,我们可以把处理代码写在 datagrid 的 mousedown 事件处理程序中,用 hitTest 判断选中的是哪一行哪一列的那个格子,然后就 select 那一行。
但是,……。当你照着做一下就会发现,不对了!每次点击了以后,还是老样子,焦点跑到 textbox 内部去了。这……
难道是 Datagrid 偷赖没有做我们要求它做的事!哦,你冤枉它了,其实它还是执行了的!只不过执行的速度太快了,我们根本没看清人家工作的结果。是谁动了它的奶酪?
如果你看过我以前的文章,应该就不难理解:用户鼠标向 Datagrid 的一格点去- >Datagrid 先接收到焦点,执行你要求它的事件- > 然后焦点就会落入此格内嵌的 textbox 中去,使 textbox 聚焦。(详细分析,请看拙作 《 Datagrid 事件响应(一) 》 )
明白了吧,在 datagrid 刚刚执行了选中一行的操作之后,它内嵌的 textbox 就会引发一个聚焦事件,致使 datagrid 不再选中一行,而是把焦点更改到你所点击的内嵌 textbox 中去了。
所以,现在的解决思路就应该是:把代码写在焦点刚落入到 datagrid 内嵌的 textbox 中时的那个事件里。而对于 textbox 来说,焦点的落入与离开的过程都会激发什么事件,我们应该在什么事件中去写选中当前行的代码呢?
按顺序来说,焦点会引发的控件事件为:
** 顺序号 ** ** **
|
** 事件名 ** ** **
|
** 事件意义 ** ** **
---|---|---
1
|
Enter
|
焦点进入了控件
2
|
GotFocus
|
控件接收了焦点
3
|
Leave
|
输入焦点离开了控件
4
|
Validating
|
控件正在进行验证
5
|
Validated
|
控件完成了验证
6
|
LostFocus
|
控件失去焦点
那么,第一个会被引发的事件就是 Enter 了!好了,我们开工吧!
现在把要做的工作梳理一下:
(1) 找一个用于 Datagrid 的绑定数据源,使 Datagrid 有显示的数据;
(2) 要写 Datagrid 内嵌的控件的事件处理程序,当然需要重新定义 Datagrid 的 DataGridTableStyle ;
(3) 把 Enter 事件指派给每一个列风格 GridColumnStyles ;
(4) 编写一个内嵌 textbox 的 Enter 事件处理程序;
(5) 打完收工!
程序如下:
dim Dataset1 as New DataSet
Dim dt As DataTable ’
Private Sub Form1_Load( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase .Load
'构建一简单的dataset
dt = DataSet1.Tables.Add("MyTable")
dt.Columns.Add("Col1", GetType ( String ))
dt.Columns.Add("Col2", GetType ( Integer ))
Dim row, row1 As DataRow
row = dt.NewRow()
row!Col1 = "name"
row!Col2 = 123
dt.Rows.Add(row)
row1 = dt.NewRow()
row1!Col1 = "xxx"
row1!Col2 = 123
dt.Rows.Add(row1)
'构建完毕
DataGrid2.DataSource = dt
Dim ts As New DataGridTableStyle() '就是它决定了datagrid是什么样的
Dim aColumnTextColumn As DataGridTextBoxColumn '要重写的东东
DataGrid1.DataSource = dt
ts.MappingName = dt.TableName
Dim numCols As Integer
numCols = dt.Columns.Count
Dim i As Integer = 0
Do While (i < numCols) '重绘所有的列
aColumnTextColumn = New DataGridTextBoxColumn()
'夺过对textbox内落下光标的控制权
AddHandler aColumnTextColumn.TextBox.Enter, New EventHandler( AddressOf TextBoxEnterHandler)
'要更改列头名,请改下句的HeaderText值
aColumnTextColumn.HeaderText = dt.Columns(i).ColumnName
aColumnTextColumn.MappingName = dt.Columns(i).ColumnName
ts.GridColumnStyles.Add(aColumnTextColumn) '增加一种自定义的column风格
i = (i + 1)
Loop
DataGrid1.TableStyles.Clear()
DataGrid1.TableStyles.Add(ts) '增加一种自定义的表风格
End Sub
Private Sub TextBoxEnterHandler( ByVal sender As Object , ByVal e As System.EventArgs)
DataGrid1.Select(DataGrid1.CurrentRowIndex)
End Sub
运行一下,然后我们来点击看看,咦,为什么被点击的那一格会有一块空白的东东,如图 1 所示:
图 1 空白的东东
我们还有什么没考虑到?当然有,就是我最开始时所说的, Datagrid 是一个网格,在每一个单元格之间还是有它的结构存在,要不用什么去安装一个个的 textbox 呀(想一下往面团里放芝麻的过程,那个面团就是 datagrid ,芝麻就是内嵌的控件,可以是 textbox ,可以是 checkbox ,可以是 combobox ,可以是其它的许多控件。合在一起,就是……烧饼,哈!看来又饿了)。
在被选中的这一格里,由于 textbox 是聚焦了,所以 Datagrid 在这一格里的部分就部屏蔽了。现在想要把它们都选中,方法很简单,就是仿照 Datagrid 的正常操作过程来做。什么时候一行能全部被选中,当然是点击行头,从焦点的角落来说,就是这一行没有一个单元格中有焦点落下!
所以,重写一下 Enter 的事件处理程序如下,把你点击的那个 textbox 的 visible 设为 false 吧,它消失了, datagrid 的整行才能被选中:
Private Sub TextBoxEnterHandler( ByVal sender As Object , ByVal e As System.EventArgs)
Dim inner As Control = sender
inner.Visible = False
DataGrid1.Select(DataGrid1.CurrentRowIndex)
End Sub
祝大家在 SARS 的阴影中保持健康与快乐,幸福永远与勤奋的你同在! <SPAN lang=EN-US style="FONT-SIZE: 9pt; mso-bidi-font-size: 12.0pt