** Henry ** ** 手记 — WinForm Datagrid ** ** 结构剖析(一) **
韩睿 ( 2002-11-14 )
早就想动手写这个专题,但一直有疑惑自己对于 .net 的 winform 中的 Datagrid 是不是已经能够进行全面的剖析。但近来问起相关问题的人越来越多,一来是使用 .net 的程序员在增多,二来是大家对 Datagrid 的使用已经摆脱了最初的显示数据的需求,想要进行高级一点的使用,就应该对 Datagrid 的结构有一个充分的认识,本文希望能够给有这方面需求的朋友一点小帮忙。
一、 基本结构
从外形上看, Datagrid 是由多个表 (table) 组成的, table 是由行 (row) 与列 (column) 组成的,行与列的交互,组成的一个个单元 (cell) 。我们的需要就是能控制每一个 cell 的变化,从而使 row 与 column 发生变化,最终形成 table 的变化。这每一种变化都可视为是 Datagrid 中 table 的一种风格格式( style )。
我们在往 form 上部署 Datagrid 控件后,会在其属性窗口下方会出现“自动套用格式”,它们的变化多是背景色( Backcolor )与前景色( Forecolor )与字体( Font )的变化。经过本文的讲述后,您将能够实现更多的格式变化。
描述基本结构,首先请看图 1 显示的内容:
但是, Datagrid 并不能直接写入数据,在图 1 中显示的数据是由 datagrid 的 datasource (数据源)决定的。而这个 datasource 是支持 ** IEnumerable ** 接口的对象,比如: Arraylist 、 Collection 、 Dataview 、 Datarow 、 Datatable 等等。(这个问题不是本文讨论的重点,暂略过)
那么 Datagrid 的结构究竟是怎么样的?我尝试的画了一个结构图如图 2 所示:
为清晰所见,我们主要讨论 Datagrid->DatagridTableStyle->DatagridColumnStyle 这一支。我们平常所看到的默认结构 Datagrid ,即把 DatagridColumnStyle 设定为 DatagridTextBoxColumn 列结构,把 datagrid 的列设为由 textbox 组成。从而我们就可以看到图 1 显示出来的那种效果,每一个 cell 里都是一个 textbox 。同理,我们就知道如果把某一列的 DatagridColumnStyle 设定为 DatagridBoolColumn 列结构,就可以在该列中用 checkbox 控件显示与更改 boolean 类型的值了。我们甚至可以自定义某一列的列类型,加入 combox 等等,这方面内容在后文会有详述。
那么本节主要讨论的就是当 cell 是默认的 textbox 时,对 datagrid 表现出来的属性的变化,主要包括:列头、列宽、前景与背景色等。在以后的小节中,对扩展的功能进行描述,包括 Datagrid 中实现键盘与鼠标响应事件、加入自定义的列样式。
在图 1 中,我要更改列头的内容,是不是和更改表头( caption text )那样方便,只要在代码中写一句:
datagrid1.CaptionText ="Henry示例" 就行了呢?
可惜不是那么简单,正如我们在上文分析地那样,要控制某个列的内容与样式,必须通过更改 DatagridColumnStyle来实现。那么,就开工吧:
'构建一简单的dataTable作为Datagrid的数据源
Label1.Parent = DataGrid1
Label1.BackColor = Color.Transparent
Dim dt As DataTable
dt = DataSet1.Tables.Add("MyTable")
dt.Columns.Add("列1", GetType ( String ))
dt.Columns.Add("列2", GetType ( Integer ))
Dim row, row1 As DataRow
row = dt.NewRow()
row!列1 = "行1"
row!列2 = 1
dt.Rows.Add(row)
row1 = dt.NewRow()
row1!列1 = "行2"
row1!列2 = 12
dt.Rows.Add(row1)
'构建完毕
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 ‘ 数据源的列数
DataGrid1.CaptionText = "Henry示例"
Dim i As Integer = 0
Do While (i < numCols) '重绘所有的列
aColumnTextColumn = New DataGridTextBoxColumn()
'要更改列头名,请改下句的HeaderText值
aColumnTextColumn.HeaderText = dt.Columns(i).ColumnName ☆
aColumnTextColumn.MappingName = dt.Columns(i).ColumnName ☆
‘ 控制列宽与行宽
If i = 1 Then
ts.PreferredColumnWidth = 50
ts.PreferredRowHeight = 20
End If
ts.AlternatingBackColor = Color.LightGray '设定交替行的背景色
ts.GridColumnStyles.Add(aColumnTextColumn) '增加一种自定义的column风格
i = (i + 1)
Loop
DataGrid1.TableStyles.Add(ts) '增加一种自定义的表风格
'注:增加风格后,你在datagrid中实时增加新的纪录,风格仍不会变
自已定义 datagrid的TableStyle的时候,具体的步骤如上面代码如示,画成步骤图就是:先设定每一个column的样式,如果想用textbox,就定义一个:
Dim aColumnTextColumn As DataGridTextBoxColumn
想控制每一列的列头标题及其列对应的数据库内容,就必须重写 HeadText与MappingName,也是必须要声明的两个属性,否则就不能够重写了。
aColumnTextColumn.HeaderText对应的就是列头
aColumnTextColumn.MappingName必须要注意了,它对应的是真实数据库的列名,因此不能随便改动。
有了这两个属性后,一个列就生成了,如果想改变列宽,就用:
ts.PreferredColumnWidth =50
如果想 隐藏一列的话 ,就这样写:
ts.PreferredColumnWidth =0 很简单吧!
如果想让列宽根据数据内容 自适应调整 ,可以这样处理:
aColumnTextColumn.TextBox.AutoSize = True
ts.PreferredColumnWidth = aColumnTextColumn.TextBox.Width
将改变了的 DataGridTextboxCoulmn实例加入到GridColumnStyles里去,代码为:
ts.GridColumnStyles.Add(aColumnTextColumn)
将每一列都重写以后(注意,如果你想自定义一个 Datagrid的TableStyle,必须对每一列的GridColumnStyle都重写),将该自定义的Tablestyle添加到Datagrid的tablestyle里去即可:
DataGrid1.TableStyles.Add(ts)
通过这几个步骤,我们就控制了每一个 cell是Textbox的这种Datagrid的部分属性(cell的前景色与背景色变化在下一节中进行讨论)
那么,如何在 Datagrid中加入一个Checkbox列呢?相对于加入其它控件类型的column来说,还是不复杂的。
首先,我们得定义一个具有 boolean类型的列,在上面代码中,加入:
dt.Columns.Add("列3", GetType ( Boolean ))
Dim row, row1 As DataRow
row = dt.NewRow()
row!列1 = "行1"
row!列2 = 1
row!列3 = False
dt.Rows.Add(row)
row1 = dt.NewRow()
row1!列1 = "行2"
row1!列2 = 12
row1!列3 = True
dt.Rows.Add(row1)
然后就可以用如下的定义进行在 Datagrid 中内嵌 CheckBox 了,在上面的代码中补充如下代码:
Dim ac As DataGridBoolColumn = New DataGridBoolColumn()
ac.HeaderText = dt.Columns(2).ColumnName
ac.MappingName = dt.Columns(2).ColumnName
ts.GridColumnStyles.Add(ac)
当然要修改: <SPAN lang=E