DataGridView控件的使用(收集)

 

DataGridView控件的使用

新的 DataGridView .NET 2.0 中的一个新控件,是针对 .NET 1.x 中功能较差的标准 DataGrid 控件而设计的。Matthew MacDonald 在本文中论述了许多改进,包括:DataGridView 支持大量自定义和细致的格式设置、灵活的大小调整和选择、更好的性能以及更丰富的事件模型。

.NET Framework 的前两个版本(.NET 1.0 .NET 1.1)在数据绑定方面留下了明显的空白。尽管开发人员拥有一个灵活的可配置模型,可以将几乎所有的控件链接到几乎所有的数据源,但却没有一种有效的方法来显示完整的信息表。可以实现此目的的唯一工具就是 DataGrid 控件,这种控件非常适合于处理简单的演示,但是不太适合实际代码。

填补这项空白是 .NET 2.0 的主要目标之一,并且 Microsoft 已经用全新的网格控件 DataGridView 来实现此目标。DataGridView 有两个指导原则。首先,其目标是支持常见任务(如主控/详细列表、验证和数据格式设置),而不需要您编写许多代码。更重要的是,设计过程中始终考虑了扩展性,因此您可以集成所需的专用功能,而不必采用低级别的复杂编程。

本页内容
 
基本数据绑定
 
美化 DataGridView
 
使用 DataGridView 选择单元格
 DataGridView
对象
 DataGridView
样式
 
自定义单元格格式
 
按钮列
 
图像列
 
编辑 DataGridView
 
处理错误
 
验证输入
 
使用列表列约束选择
 
小结

基本数据绑定
熟悉 DataGridView 的最佳方法就是实际尝试一下,无需配置任何属性。就像 DataGrid 一样,您可以使用 DataSource 属性来绑定 DataTable 对象(或从 DataTable 派生的对象)。

Dim ds As DataSet = GetDataSet()
DataGridView1.DataSource = ds.Tables("Customers")

DataGrid 不同的是,DataGridView 一次只能显示一个表。如果绑定整个 DataSet,则不会显示任何数据,除非您使用要显示的表名设置了 DataMember 属性。

DataGridView1.DataSource = ds
DataGridView1.DataMember = "Customers"

基本的 DataGridView 显示遵循以下几项简单的规则:

? 为数据源中的每个字段创建一列。
 
?
使用字段名称创建列标题。列标题是固定的,这意味着用户在列表中向下移动时列标题不会滚动出视图。
 
?
支持 Windows XP 视觉样式。您会注意到列标题具有新式的平面外观,并且当用户将鼠标移到其上时会突出显示。
 

DataGridView 还包括几个您可能不会立即注意到的默认行为:

? 允许就地编辑。用户可以在单元格中双击或按 F2 来修改当前值。唯一的例外是将 DataColumn.ReadOnly 设置为 True 的字段(如当前示例中的 OrderID 字段)。
 
?
支持自动排序。用户可以在列标题中单击一次或两次,基于该字段中的值按升序或降序对值进行排序。默认情况下,排序时会考虑数据类型并按字母或数字顺序进行排序。字母顺序区分大小写。
 
?
允许不同类型的选择。用户可以通过单击并拖动来突出显示一个单元格、多个单元格或多个行。单击 DataGridView 左上角的方块可以选择整个表。
 
?
支持自动调整大小功能。用户可以在标题之间的列分隔符上双击,使左边的列自动按照单元格的内容展开或收缩。
 

返回页首
美化 DataGridView
DataGridView
的默认外观仅仅比 DataGrid 略有改进,但是使用几项快速调整功能,您可以将其显著改进。

其中的一个问题就是列无法自动展开以适合其包含的数据。您可以使用 DataGridView.AutoSizeColumns() 方法以及 DataGridViewAutoSizeColumnCriteria 枚举中的某个值来解决此问题。您可以选择根据标题文本、当前显示的行或表中的所有行的的宽度来调整列宽。

' 根据标题或此列的某一行中
'
最长一段文本的宽度调整
'
列宽。
DataGridView1.AutoSizeColumns( _
DataGridViewAutoSizeColumnCriteria.HeaderAndRows)

请记住,此方法必须在绑定数据后调用,否则不会产生任何效果。你可能还需要在用户编辑数据后使用它(可能在响应 DataGridView.CellValueChanged 等事件时)。

如果不增加列宽,则可以更改行高。默认情况下,列中的文本会跨越多行。如果您使用 DataGridView.AutoSizeRows() 方法,则行会根据其中的内容调整高度。使用此方法前,您可能希望增加列宽,尤其是在字段包含大量文本时。例如,以下代码片段使说明列的列宽增加为原列宽的四倍,然后调整行高以容纳其内容。

DataGridView.Columns("Description").Width *= 4
DataGridView.AutoSizeRows( _
DataGridViewAutoSizeRowsMode.HeaderAndColumnsAllRows)

1 比较了自动调整 DataGridView 大小的各种方法。

另一个合理的更改是清理每一列中显示的标题文本。例如,标题“Order Date”比字段名称“OrderDate”看上去更为专业。这项更改很容易进行。您只需从 DataGridView.Columns 集合中检索相应的 DataGridViewColumn,并修改其 HeaderText 属性:

DataGridView.Columns("OrderID").HeaderText = "Order ID"

返回页首
使用 DataGridView 选择单元格
默认情况下,DataGridView 允许自由选择。用户可以突出显示单元格或单元格组,可以一次突出显示所有单元格(通过单击网格右上角的方块),还可以突出显示一行或多行(通过在行标题列中单击)。根据选择模式,用户甚至能够通过选择列标题来选择一列或多列。通过使用 DataGridViewSelectionMode 枚举中的某个值来设置 DataGridView.SelectionMode 属性,可以控制此行为,如下所述:

? CellSelect:用户可以选择单元格,但不能选择整个行或标题。如果 DataGridView.MultiSelect True,则用户可以选择多个单元格。
 
? FullColumnSelect
:单击列标题只能选择整个列。如果 DataGridView.MultiSelect True,则用户可以选择多个列。使用此模式时,单击列标题不会对网格进行排序。
 
? FullRowSelect
:单击行标题只能选择整个行。如果 DataGridView.MultiSelect True,则用户可以选择多个行。
 
? ColumnHeaderSelect
:用户可以使用 CellSelect FullColumnSelect 选择模式。使用此模式时,单击列标题不会对网格进行排序。
 
? RowHeaderSelect
:用户可以使用 CellSelect FullRowSelect 选择模式。这是默认的选择模式。
 

通过 DataGridView,可以使用以下三个属性方便地检索选定的单元格:SelectedCellsSelectedRows SelectedColumns。无论使用的是哪种选择模式,SelectedCells 都始终返回 DataGridViewCell 对象的集合。另一方面,如果使用行标题选择了整个行,则 SelectedRows 只返回信息,而如果使用列标题选择了整个列,则 SelectedColumns 也只返回信息。

例如,以下代码片段将检查选定的整个行。只要找到一行,它就会在消息框中显示 CustomerID 列中的相应值:

For Each SelectedRow As DataGridViewRow In _
DataGridView1.SelectedRows
MessageBox.Show( _
SelectedRow.Cells("CustomerID").Value)
Next

使用 CurrentCell CurrentCellAddress 属性检索对当前单元格的引用也同样简单。使用 DataGridView 时,您会注意到当前单元格被一个矩形围住,看起来像是一个用黑色虚线绘制的方框。这就是用户当前所在的位置。

CurrentCellAddress 属性是只读的,但是您可以使用 CurrentCell 以编程方式更改当前位置。完成此操作后,DataGridView 将被滚动以使当前位置可见。

' 移至第十一行的第四个单元格。
DataGridView.CurrentCell = _
DataGridView.Rows(10).Cells(3)

返回页首
DataGridView
对象
到目前为止,您已经了解了如何与当前选定的一组行、单元格和列进行交互。DataGridView 提供了两个关键集合,用于处理整个数据集。这两个集合分别是 ColumnsDataGridViewColumn 对象的集合)和 RowsDataGridViewRow 对象的集合,每个对象都引用一组 DataGridViewCell 对象的集合)。图 2 显示了对象模型。

一般而言,您将使用 DataGridViewColumn 对象来配置列显示属性、格式设置及标题文本,而使用 DataGridViewRow DataGridViewCell 对象从绑定的记录中检索实际数据。在 DataGridViewCell 中修改数据时,处理方式与用户编辑的方式相同:引发相应的 DataGridView 更改事件,并且修改底层的 DataTable

现在您已经了解了 DataGridView 对象模型,因此可以轻松地创建遍历该表的代码。要选择行、列或单元格,只需找到对应的 DataGridViewRowDataGridViewColumn DataGridViewCell 对象,并将 IsSelected 属性设置为 True

以下示例以编程方式选择 OrderID 字段的值小于 100 的所有行:

For Each Row As DataGridViewRow In DataGridView1.Rows
If Row.Cells("OrderID").Value < 100 Then
Row.Selected = True
End If
Next

值得一提的是,有几个从 DataGridViewColumn 派生的不同的类。这些类可以控制在单元格中显示和编辑值的方式。.NET 包括五个预先创建的 DataGridView 列类:DataGridViewButtonColumnDataGridViewCheckBoxColumnDataGridViewComboBoxColumnDataGridViewImageColumn DataGridViewTextBoxColumn

返回页首
DataGridView
样式
设计 DataGridView 时面临的挑战之一就是创建一个格式设置系统,该系统要能够足够灵活地应用不同级别的格式设置,而对于非常大的表又要保持高效。从灵活性角度来看,最好的方法是允许开发人员分别配置每个单元格。但是从效率角度来看,这种方法可能是有害的。包含数千行的表中具有好几万个单元格,维护每个单元格的不同格式肯定会浪费很多内存。

为解决此问题,DataGridView 通过 DataGridViewCellStyle 对象来实现多层模型。DataGridViewCellStyle 对象表示单元格的样式,并且包括如颜色、字体、对齐、换行和数据格式等详细信息。您可以创建一个 DataGridViewCellStyle 来指定整个表的默认格式。此外,还可以指定列、行和各个单元格的默认格式。格式设置的越细致、创建的 DataGridViewCellStyle 对象越多,该解决方案的可伸缩性也就越小。但是,如果您主要使用基于列和基于行的格式设置,并且只是偶尔设置各个单元格的格式,则与 DataGrid 相比,DataGridView 不需要太多内存。

DataGridView 应用格式设置时,将遵循以下优先顺序(从最高到最低):

1. DataGridViewCell.Style
2. DataGridViewRow.DefaultCellStyle
3. DataGridView.AlternatingRowsDefaultCellStyle
4. DataGridView.RowsDefaultCellStyle
5. DataGridViewColumn.DefaultCellStyle
6. DataGridView.DefaultCellStyle

重要的是要清楚:样式对象不是以全有/全无的方式应用的,DataGridView 会检查每个属性。例如,假设您的单元格使用 DataGridViewCell.Style 属性来应用自定义字体,但没有设置自定义前景色。结果,该字体设置将覆盖任何其他样式对象中的字体信息,但如果层次结构中下一个样式对象的前景色不为空,则将从该对象继承前景色(在这种情况下为 DataGridViewRow.DefaultCellStyle)。

DataGridViewCellStyle 定义了两种格式设置:数据和外观。数据格式设置描述显示数据绑定值之前如何对其进行修改。这种格式设置通常包括使用格式设置字符串将数字或日期值转换为文本。要使用数据格式设置,只需使用 DataGridViewCellStyle.Format 属性设置格式定义或自定义格式字符串即可。

例如,以下代码片段对 UnitCost 字段中的所有数字进行格式设置,以将它们显示为货币值,保留两位小数并加上在区域设置中定义的相应货币符号:

DataGridView1.Columns("UnitCost"). _
DefaultCellStyle.Format = "C"

外观格式设置包括颜色和格式等表面细节。例如,以下代码右对齐 UnitCost 字段、应用粗体并将单元格的背景更改为黄色:

DataGridView1.Columns("UnitCost"). _
DefaultCellStyle.Font = _
New Font(DataGridView.Font, FontStyle.Bold)
DataGridView1.Columns("UnitCost"). _
DefaultCellStyle.Alignment = _
DataGridViewContentAlignment.MiddleRight
DataGridView1.Columns("UnitCost"). _
DefaultCellStyle.BackColor = Color.LightYellow

其他与格式设置相关的属性包括 ForeColorSelectionForeColorSelectionBackColorWrapMode(控制文本在空间允许时是跨越多行还是直接截断)及 NullValue(将替代 Null 值的值)。

DataGridView 还包括一个设计器,用于在设计时配置列样式。只需从“Properties”(属性)窗口中选择“DataGridView Properties”DataGridView 属性)链接,或者从各种预先创建的样式设置中选择“AutoFormat”(自动套用格式)。

返回页首
自定义单元格格式
单元格格式设置的第一种方法是设置更高级别的 DataGridViewDataGridViewColumn DataGridViewRow 属性。但是,有时您需要为特定单元格单独设置样式。例如,您可能需要在列中的数据大于或小于某个值时标记该列中的数据。例如,突出显示项目计划列表中已过去的到期日期,或者在销售分析中突出显示负收益率。在这两种情况下,您需要对单独的单元格进行格式设置。

了解 DataGridView 对象模型后,您可能想要遍历特定列中的单元格集合,以寻找要突出显示的值。这种方法是可行的,但不是最好的方法。关键问题是如果用户编辑了数据,或者如果代码更改了绑定的数据源,不会对单元格的突出显示情况进行相应的更新。

幸运的是,DataGridView 针对此目的提供了 CellFormatting 事件。CellFormatting 只在显示单元格值之前引发。通过该事件,可以基于单元格的内容来更新单元格样式。以下示例检查特定的客户并相应地标记单元格:

Private Sub DataGridView1_CellFormatting( _
ByVal sender As System.Object, _
ByVal e As System.Windows.Forms. _
DataGridViewCellFormattingEventArgs) _
Handles DataGridView1.CellFormatting

' 检查该列是否正确。
If DataGridView1.Columns(e.ColumnIndex).Name = _
"CustomerID" Then
'
检查该值是否正确。
If e.Value = "ALFKI" Then
e.CellStyle.ForeColor = Color.Red
e.CellStyle.BackColor = Color.Yellow
End If
End If
End Sub

样式不是影响网格外观的唯一细节。您还可以隐藏列、在不同位置之间移动列,并冻结列,使这些列在用户滚动到右端时仍然可见。这些功能都是通过 DataGridViewColumn 类的属性提供的,如下所述:

? DisplayIndex:设置列在 DataGridView 中显示的位置。例如,DisplayIndex 值为 0 的列将自动显示在最左边的列中。如果多个列具有相同的 DisplayIndex,则先显示最先出现在该集合中的列。因此,如果您使用 DisplayIndex 将一列向左移动,则可能还需要设置最左边的列的 DisplayIndex,以将其向右移动。最初,DisplayIndex DataGridView.Columns 集合中 DataGridViewColumn 对象的索引相匹配。
 
? Frozen
:如果为 True,则该列将始终可见并且固定在表的左侧,即使用户为查看其他列而滚动到右侧亦如此。
 
? HeaderText
:设置将在列标题中显示的文本。
 
? Resizable
MinimumWidth:将 Resizable 设置为 False,以防止用户调整列宽;或者将 MinimumWidth 设置为允许的最小像素数目。
 
? Visible
:要隐藏列,请将此属性设置为 False
 

返回页首
按钮列
DataGridView
提供的一种列是 DataGridViewButtonColumn,这种列在每一项旁边显示一个按钮。您可以响应此按钮的单击事件,并使用它启动其他操作或显示新的表单。

以下示例使用按钮文字“Details...”创建简单的按钮列:

' 创建按钮列。
Dim Details As New DataGridViewButtonColumn()
Details.Name = "Details"

' 关闭数据绑定并显示静态文本。
'
(但是,您可以通过设置 DataPropertyName
'
属性来使用该表中的属性。)
Details.DisplayTextAsFormattedValue = False
Details.Text = "Details..."

' 清除标题。
Details.HeaderText = ""

' 添加该列。
DataGridView1.Columns.Insert( _
DataGridView1.Columns.Count, Details)

3 显示了包含新列的网格。以下代码会对任何行中的按钮单击事件做出反应,并显示相应的记录信息:

Private Sub DataGridView1_CellClick( _
ByVal sender As System.Object, _
ByVal e As System.Windows.Forms. _
DataGridViewCellEventArgs) _
Handles DataGridView1.CellClick

If DataGridView1.Columns(e.ColumnIndex).Name = _
"Details" Then
MessageBox.Show("You picked " & _
DataGridView1.Rows(e.RowIndex). _
Cells("CustomerID").Value)
End If
End Sub

比较现实的方案是,在此时创建并显示一个新窗口,并将有关选定记录的信息传递到这个新窗口,以便查询并显示完整的信息。

返回页首
图像列
DataGridView
提供的另一种列是 DataGridViewImageColumn,这种列将在单元格边框内显示一个图片。您可以设置 DataGridViewImageColumn.Layout 属性以便配置图片在单元格中的显示方式:是将单元格扩展到适当的大小,还是将直接剪裁太大的图像。

使用 DataGridViewImageColumn 的方法有两种。首先,您可以采用与 DataGridViewButtonColumn 相同的方式手动创建并添加该列。如果您需要显示 DataSet 本身不提供的相关图像信息,则此列非常有用。例如,您可能需要获取文件名(如 ProductPic002.gif),从网络驱动器读取相应的文件,然后在网格中显示该文件。为完成此操作,您需要对 DataGridView 事件(如 CellFormatting)做出反应,以便读取相应行的图片、获取图像数据并使用该列中的 Value 属性将其插入。

如果 DataSet 包含不需要任何手动操作的二进制图片数据,那么事情会变得更加简单。例如 SQL Server Pubs 数据库中的 pub_info 表,该表包含公司徽标。绑定至此表时,您不需要执行任何额外步骤,DataGridView 将自动识别出您正在使用图像,并会创建所需的 DataGridViewImageColumn。(有关这项技术的示例,请参阅本文的下载内容。)

返回页首
编辑 DataGridView
众所周知,DataGrid 的用户输入功能很不灵活,您几乎没有办法自定义单元格验证方式及错误报告方式。而另一方面,DataGridView 允许您通过对在编辑过程的所有阶段中引发的大量不同事件做出反应来控制其行为。

默认情况下,当用户用鼠标双击单元格或按 F2 键时,DataGridView 单元格将进入编辑模式。您还可以通过将 DataGridView.EditCellOnEnter 属性设置为 True,对 DataGridView 进行配置,以便当用户移到该单元格后,该单元格立即切换到编辑模式。您还可以使用 DataGridView BeginEdit()CancelEdit()CommitEdit() EndEdit() 方法通过编程方式开始和停止单元格编辑。用户编辑单元格时,行标题将显示一个铅笔状的编辑图标。

用户可以通过按 Esc 键来取消编辑。如果将 EditCellOnEnter 属性设置为 True,则单元格仍将处于编辑模式,但是所有更改都将被放弃。要提交更改,用户只需移到新的单元格,或将焦点切换到其他控件。如果您的代码可以移动当前单元格的位置,则此代码也会提交更改。

为防止单元格被编辑,可以设置 DataGridViewCellDataGridViewColumnDataGridViewRow DataGridView ReadOnly 属性(取决于您是要防止对该单元格进行更改、对该列中的所有单元格进行更改、对该行中的所有单元格进行更改,还是要防止对该表中的所有单元格进行更改)。DataGridView 还提供了 CellBeginEdit 事件,用于取消尝试的编辑。

返回页首
处理错误
默认情况下,DataGridViewTextBoxColumn 允许用户输入任何字符,包括当前单元格中可能不允许使用的那些字符。例如,用户可以在数字字段中键入非数字字符,也可以指定与 DataSet 中定义的 ForeignKeyConstraint UniqueConstraint 冲突的值。DataGridView 采用不同的方式来处理这些问题:

? 如果可以将编辑的值转换为所需的数据类型(例如,用户在数字列中键入了文本),则用户将不能提交更改或导航到其他行。而必须取消更改或编辑值。
 
?
如果编辑的值与 DataSet 中的约束冲突,则用户通过导航到其他行或按 Enter 键提交更改后,更改将被立即取消。
 

这些处理方式适用于大多数情况。但是,如果需要,您也可以通过响应 DataGridView.DataError 事件来参与错误处理,该事件是在 DataGridView 侦听到来自数据源的错误时引发的。

返回页首
验证输入
验证是一项与错误处理稍有不同的任务。通过错误处理,您可以处理由 DataSet 报告的问题。而通过验证,您可以捕获您自己定义的错误情况,例如 DataSet 中允许的数据在应用程序中却没有意义。

当用户通过导航到新的单元格提交更改时,DataGridView 控件将引发 CellValidating CellValidated 事件。这些事件之后是 RowValidating RowValidated 事件。您可以响应这些事件,检查用户输入的值是否正确,并执行所需的任何后期处理。如果值无效,通常您会通过两种方式来做出响应,即取消更改和单元格导航(通过将 EventArgs 对象的 Cancel 属性设置为 True),或者设置某种错误文本来提醒用户。可以将错误文本置于其他控件中,也可以使用相应的 DataGridViewRow DataGridViewCell ErrorText 属性在 DataGrid 中显示错误文本:

? 设置 DataGridViewCell.ErrorText 时,单元格中将显示感叹号图标。将鼠标悬停在此图标上将显示错误消息。
 
?
设置 DataGridViewRow.ErrorText 时,行左侧的行标题中将显示感叹号图标。将鼠标悬停在此图标上将显示错误消息。
 

通常,您会结合使用这两种属性,并设置行和单元格中的错误消息。以下示例检查 CompanyName 字段中太长的文本输入。如果发现有问题的值,则会将错误符号(红色的感叹号)添加到单元格中,并显示描述该问题的工具提示文本。

Private Sub DataGridView1_CellValidating( _
ByVal sender As System.Object, _
ByVal e As System.Windows.Forms. _
DataGridViewCellValidatingEventArgs) _
Handles DataGridView1.CellValidating

If DataGridView1.Columns(e.ColumnIndex).Name = _
"CompanyName" Then
If CType(e.FormattedValue, String).Length > _
50 Then
DataGridView1.Rows( _
e.RowIndex).Cells(e.ColumnIndex). _
ErrorText = _
"The company name is too long."
End If
End If
End Sub

返回页首
使用列表列约束选择
使用验证可以捕获任何错误情况。但是,这种方法不一定是最好的,因为它允许用户输入无效的内容,然后在事实出现后尝试改正无效输入。更好的解决方案是使用户在一开始就无法输入任何无效的内容。

一个常见例子就是您需要将列限制在预定义值列表的范围内。在此示例中,对于用户而言,最简单的办法是从列表中选择正确的值,而不要手动键入值。最大的优势在于,您可以使用 DataGridViewComboBoxColumn 非常方便地实现此设计。

可以使用 Items 集合手动为 DataGridViewComboBoxColumn 添加项列表,就像使用 ListBox 一样。此外,还可以将 DataGridViewComboBoxColumn 绑定到其他数据源。在这种情况下,您可以使用 DataSource 属性来指定数据源,并使用 DisplayMember 属性指示列中应显示的值,以及使用 ValueMember 属性指定底层列值应使用的值。

为了演示这种情况,来看看下一个有关 Products 表的示例。此表中的每一条记录都通过其 CategoryID 字段链接至 Categories 表中的记录。要更改产品类别,用户需要记住正确的 ID,并将其输入到 CategoryID 字段中。更好的解决方案是使用与 Categories 表绑定的 DataGridViewComboBoxColumn。此列将使用 CategoryName 作为显示值,但是会将 CategoryID 作为真正的底层值。此列仍将通过 DataPropertyName 属性与 Products 表绑定在一起,这意味着当用户从列表中选择新的 Category 时,产品记录的 CategoryID 字段将自动更改。

以下是配置此表所需的代码:

' 删除自动生成的 CategoryID 列。
DataGridView1.Columns.Remove("CategoryID")

' CategoryID 创建列表列。
Dim List As New DataGridViewComboBoxColumn()
List.DisplayIndex = 0
List.HeaderText = "Category"

' 此列绑定至
' Products.CategoryID
字段。
List.DataPropertyName = "CategoryID"

' 该列表将从 Categories 表获得数据。
List.DataSource = ds.Tables("Categories")
List.DisplayMember = "CategoryName"
List.ValueMember = "CategoryID"

' 添加该列。
DataGridView1.Columns.Add(List)

返回页首
小结
本文概要介绍了最值得期待的 .NET 新控件之一:DataGridView。与 DataGrid 不同的是,DataGridView 适用于各种不同的现实情况——无论是要处理数据绑定和用户编辑,还是仅涉及静态文本显示,都可以采用 DataGridView。简而言之,本文让您近距离了解了 .NET Framework 提供的一体化数据解决方案,以及 Windows 窗体开发人员升级至 .NET 2.0 的最引人注目的原因之一。

.NET 2.0 - WinForm Control - DataGridView 编程36计(一)

目录:


 DataGridView  取得或者修改当前单元格的内容:

GO TO TOP

当前单元格指的是 DataGridView 焦点所在的单元格,它可以通过 DataGridView 对象的 CurrentCell 属性取得。如果当前单元格不存在的时候,返回Nothing(C#null)

[VB.NET]
取得当前单元格内容
Console.WriteLine(DataGridView1.CurrentCell.Value)
取得当前单元格的列 Index
Console.WriteLine(DataGridView1.CurrentCell.ColumnIndex)
' 取得当前单元格的行 Index
Console.WriteLine(DataGridView1.CurrentCell.RowIndex)

[C#]
// 取得当前单元格内容
Console.WriteLine(DataGridView1.CurrentCell.Value);
// 取得当前单元格的列 Index
Console.WriteLine(DataGridView1.CurrentCell.ColumnIndex);
// 取得当前单元格的行 Index
Console.WriteLine(DataGridView1.CurrentCell.RowIndex);


另外,使用 DataGridView.CurrentCellAddress 属性(而不是直接访问单元格)来确定单元格所在的行:DataGridView.CurrentCellAddress.Y 和列: DataGridView.CurrentCellAddress.X 。这对于避免取消共享行的共享非常有用。

当前的单元格可以通过设定 DataGridView 对象的 CurrentCell 来改变。可以通过 CurrentCell 来设定
DataGridView
的激活单元格。将 CurrentCell 设为 Nothing(null) 可以取消激活的单元格。

[VB.NET]
设定 (0, 0)  为当前单元格
DataGridView1.CurrentCell = DataGridView1(0, 0)

[C#]
// 设定 (0, 0)  为当前单元格
DataGridView1.CurrentCell = DataGridView1[0, 0];


在整行选中模式开启时,你也可以通过 CurrentCell 来设定选定行。

        /// <summary>
        
/// 
向下遍历
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        
{
            
int row = this.dataGridView1.CurrentRow.Index + 1;
            
if (row > this.dataGridView1.RowCount - 1)
                row = 0;
            
this.dataGridView1.CurrentCell = this.dataGridView1[0, row];  
        }

        
/// <summary>
        
/// 
向上遍历
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void button5_Click(object sender, EventArgs e)
        
{
            
int row = this.dataGridView1.CurrentRow.Index - 1;
            
if (row < 0)
                row = 
this.dataGridView1.RowCount - 1;
            
this.dataGridView1.CurrentCell = this.dataGridView1[0, row];  
        }


*
注意: this.dataGridView 的索引器的参数是: columnIndex, rowIndex 或是 columnName, rowIndex
这与习惯不同。


 DataGridView  设定单元格只读:

GO TO TOP

1使用 ReadOnly 属性
 如果希望,DataGridView 内所有单元格都不可编辑,那么只要:

[VB.NET]
设置 DataGridView1 为只读
DataGridView1.ReadOnly = True

[C#]
// 设置 DataGridView1 为只读
DataGridView1.ReadOnly = true;

此时,用户的新增行操作和删除行操作也被屏蔽了。

 如果希望,DataGridView 内某个单元格不可编辑,那么只要:

[VB.NET]
' 设置 DataGridView1 的第2列整列单元格为只读
DataGridView1.Columns(1).ReadOnly = True

' 设置 DataGridView1 的第3行整行单元格为只读
DataGridView1.Rows(2).ReadOnly = True

' 设置 DataGridView1 [00]单元格为只读
DataGridView1(0, 0).ReadOnly = True

[C#]
// 设置 DataGridView1 的第2列整列单元格为只读
DataGridView1.Columns[1].ReadOnly = true;

// 设置 DataGridView1 的第3行整行单元格为只读
DataGridView1.Rows[2].ReadOnly = true;

// 设置 DataGridView1 [00]单元格为只读
DataGridView1[0, 0].ReadOnly = true;


2
使用 EditMode 属性
DataGridView.EditMode
属性被设置为 DataGridViewEditMode.EditProgrammatically 时,用户就不能手动编辑单元格的内容了。但是可以通过程序,调用 DataGridView.BeginEdit 方法,使单元格进入编辑模式进行编辑。

[VB.NET]
DataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically

[C#]
DataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically;


3
根据条件设定单元格的不可编辑状态
当一个一个的通过单元格坐标设定单元格 ReadOnly 属性的方法太麻烦的时候,你可以通过 CellBeginEdit 事件来取消单元格的编辑。

[VB.NET]
'CellBeginEdit 事件处理方法
Private Sub DataGridView1_CellBeginEdit(ByVal sender As Object, _
        
ByVal e As DataGridViewCellCancelEventArgs) _
        
Handles DataGridView1.CellBeginEdit
    
Dim dgv As DataGridView = CType(sender, DataGridView)
    
' 是否可以进行编辑的条件检查
    If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _
        
Not CBool(dgv("Column2", e.RowIndex).Value) Then
        
' 取消编辑
        e.Cancel = True
    
End If
End Sub

[C#]
// CellBeginEdit 事件处理方法
private void DataGridView1_CellBeginEdit(object sender,
    DataGridViewCellCancelEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;
    
//是否可以进行编辑的条件检查
    if (dgv.Columns[e.ColumnIndex].Name == "Column1" &&
        !(
bool)dgv["Column2", e.RowIndex].Value)
    {
        
// 取消编辑
        e.Cancel = true;
    }
}


 DataGridView  不显示最下面的新行:

GO TO TOP

通常 DataGridView 的最下面一行是用户新追加的行(行头显示 * )。如果不想让用户新追加行即不想显示该新行,可以将 DataGridView 对象的 AllowUserToAddRows 属性设置为 False

[VB.NET]
' 设置用户不能手动给 DataGridView1 添加新行
DataGridView1.AllowUserToAddRows = False

[C#]
// 设置用户不能手动给 DataGridView1 添加新行
DataGridView1.AllowUserToAddRows = false;

但是,可以通过程序: DataGridViewRowCollection.Add DataGridView 追加新行。

补足:如果 DataGridView DataSource 绑定的是 DataView, 还可以通过设置 DataView.AllowAdd
属性为 False 来达到同样的效果。


 DataGridView  判断新增行:

GO TO TOP

DataGridViewAllowUserToAddRows属性为True时也就是允许用户追加新行的场合下,DataGridView的最后一行就是新追加的行(*)。使用 DataGridViewRow.IsNewRow 属性可以判断哪一行是新追加的行。另外,通过DataGridView.NewRowIndex 可以获取新行的行序列号。在没有新行的时候,NewRowIndex = -1

[VB.NET]
If DataGridView1.CurrentRow.IsNewRow Then
    Console.WriteLine("
当前行为新追加行。")
Else
    Console.WriteLine("
当前行不是新追加行。")
End If


 DataGridView  行的用户删除操作的自定义:

GO TO TOP

1无条件的限制行删除操作。
默认时,DataGridView 是允许用户进行行的删除操作的。如果设置 DataGridView对象的AllowUserToDeleteRows属性为 False 时,用户的行删除操作就被禁止了。

[VB.NET]
' 禁止DataGridView1的行删除操作。
DataGridView1.AllowUserToDeleteRows = False

[C#]
// 禁止DataGridView1的行删除操作。
DataGridView1.AllowUserToDeleteRows = false;


但是,通过 DataGridViewRowCollection.Remove 还是可以进行行的删除。
补足:如果 DataGridView 绑定的是 DataView 的话,通过 DataView.AllowDelete 也可以控制行的删除。

2
行删除时的条件判断处理。
用户在删除行的时候,将会引发 DataGridView.UserDeletingRow 事件。在这个事件里,可以判断条件并取消删除操作。

[VB.NET]
' DataGridView1 UserDeletingRow 事件
Private Sub DataGridView1_UserDeletingRow(ByVal sender As Object, _
        
ByVal e As DataGridViewRowCancelEventArgs) _
        
Handles DataGridView1.UserDeletingRow
    
删除前的用户确认。
    If MessageBox.Show("确认要删除该行数据吗?", "删除确认", _
        MessageBoxButtons.OKCancel, MessageBoxIcon.Question) <> _
            Windows.Forms.DialogResult.OK 
Then
       
如果不是 OK,则取消。
        e.Cancel = True
    
End If
End Sub

[C#]
// DataGridView1 UserDeletingRow 事件
private void DataGridView1_UserDeletingRow(
    
object sender, DataGridViewRowCancelEventArgs e)
{
    
// 删除前的用户确认。
    if (MessageBox.Show("确认要删除该行数据吗?", "删除确认",
        MessageBoxButtons.OKCancel,
        MessageBoxIcon.Question) != DialogResult.OK)
    {
       
// 如果不是 OK,则取消。
        e.Cancel = true;
    }
}


 DataGridView  行、列的隐藏和删除:

GO TO TOP

1行、列的隐藏

[VB.NET]
' DataGridView1的第一列隐藏
DataGridView1.Columns(0).Visible = False
' DataGridView1的第一行隐藏
DataGridView1.Rows(0).Visible = False

[C#]
// DataGridView1的第一列隐藏
DataGridView1.Columns[0].Visible = false;
// DataGridView1的第一行隐藏
DataGridView1.Rows[0].Visible = false;


2
行头、列头的隐藏

[VB.NET]
列头隐藏
DataGridView1.ColumnHeadersVisible = False
行头隐藏
DataGridView1.RowHeadersVisible = False

[C#]
// 列头隐藏
DataGridView1.ColumnHeadersVisible = false;
// 行头隐藏
DataGridView1.RowHeadersVisible = false;


3
行和列的删除

[VB.NET]
'
删除名为"Column1"的列
DataGridView1.Columns.Remove("Column1")
' 删除第一列
DataGridView1.Columns.RemoveAt(0)
' 删除第一行
DataGridView1.Rows.RemoveAt(0)

[C#]
'
删除名为"Column1"的列
DataGridView1.Columns.Remove("Column1");
' 删除第一列
DataGridView1.Columns.RemoveAt(0);
' 删除第一行
DataGridView1.Rows.RemoveAt(0);


4
删除选中行

[VB.NET]
For Each r As DataGridViewRow In DataGridView1.SelectedRows
    
If Not r.IsNewRow Then
        DataGridView1.Rows.Remove(r)
    
End If
Next

[C#]
foreach (DataGridViewRow r in DataGridView1.SelectedRows)
{
    
if (!r.IsNewRow)
    {
        DataGridView1.Rows.Remove(r);
    }
}


DataGridView 禁止列或者行的Resize

GO TO TOP

1禁止所有的列或者行的Resize

[VB.NET]
' 禁止用户改变DataGridView1的所有列的列宽
DataGridView1.AllowUserToResizeColumns = False

'禁止用户改变DataGridView1の所有行的行高
DataGridView1.AllowUserToResizeRows = False

[C#]
// 禁止用户改变DataGridView1的所有列的列宽
DataGridView1.AllowUserToResizeColumns = false;

//禁止用户改变DataGridView1の所有行的行高
DataGridView1.AllowUserToResizeRows = false;


但是可以通过 DataGridViewColumn.Width 或者 DataGridViewRow.Height 属性设定列宽和行高。

2
禁止指定行或者列的Resize

[VB.NET]
禁止用户改变DataGridView1的第一列的列宽
DataGridView1.Columns(0).Resizable = DataGridViewTriState.False

禁止用户改变DataGridView1的第一列的行宽
DataGridView1.Rows(0).Resizable = DataGridViewTriState.False

[C#]
// 禁止用户改变DataGridView1的第一列的列宽
DataGridView1.Columns[0].Resizable = DataGridViewTriState.False;

// 禁止用户改变DataGridView1的第一列的行宽
DataGridView1.Rows[0].Resizable = DataGridViewTriState.False;


关于 NoSet

Resizable 属性设为 DataGridViewTriState.NotSet 时,实际上会默认以 DataGridView AllowUserToResizeColumns   AllowUserToResizeRows 的属性值进行设定。比如: DataGridView.AllowUserToResizeColumns = False Resizable NoSet 设定时,Resizable = False

判断 Resizable 是否是继承设定了 DataGridView AllowUserToResizeColumns   AllowUserToResizeRows 的属性值,可以根据 State 属性判断。如果 State 属性含有 ResizableSet,那么说明没有继承设定。

3列宽和行高的最小值的设定

[VB.NET]
第一列的最小列宽设定为 100
DataGridView1.Columns(0).MinimumWidth = 100

第一行的最小行高设定为 50
DataGridView1.Rows(0).MinimumHeight = 50

[C#]
// 第一列的最小列宽设定为 100
DataGridView1.Columns[0].MinimumWidth = 100;

// 第一行的最小行高设定为 50
DataGridView1.Rows[0].MinimumHeight = 50;


4)
禁止用户改变行头的宽度以及列头的高度

[VB.NET]
禁止用户改变列头的高度
DataGridView1.ColumnHeadersHeightSizeMode = _
    DataGridViewColumnHeadersHeightSizeMode.DisableResizing

' 禁止用户改变行头的宽度
DataGridView1.RowHeadersWidthSizeMode = _
    DataGridViewRowHeadersWidthSizeMode.EnableResizing

[C#]
// 禁止用户改变列头的高度
DataGridView1.ColumnHeadersHeightSizeMode =
    DataGridViewColumnHeadersHeightSizeMode.DisableResizing;

// 禁止用户改变行头的宽度
DataGridView1.RowHeadersWidthSizeMode =
    DataGridViewRowHeadersWidthSizeMode.EnableResizing;


DataGridView 列宽和行高自动调整的设定:

GO TO TOP


1)
设定行高和列宽自动调整

[VB.NET]
' 设定包括Header和所有单元格的列宽自动调整
DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells

' 设定包括Header和所有单元格的行高自动调整
DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells

[C#]
// 设定包括Header和所有单元格的列宽自动调整
DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

// 设定包括Header和所有单元格的行高自动调整
DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;


AutoSizeColumnsMode
属性的设定值枚举请参照 msdn DataGridViewAutoSizeRowsMode 说明。

2
)指定列或行自动调整

[VB.NET]
第一列自动调整
DataGridView1.Columns(0).AutoSizeMode = _
    DataGridViewAutoSizeColumnMode.DisplayedCells

[C#]
// 第一列自动调整
DataGridView1.Columns[0].AutoSizeMode =
    DataGridViewAutoSizeColumnMode.DisplayedCells;


AutoSizeMode
设定为 NotSet  时,默认继承的是  DataGridView.AutoSizeColumnsMode 属性。

3)
设定列头的高度和行头的宽度自动调整

[VB.NET]
'  设定列头的宽度可以自由调整
DataGridView1.ColumnHeadersHeightSizeMode = _
    DataGridViewColumnHeadersHeightSizeMode.AutoSize

'  设定行头的宽度可以自由调整
DataGridView1.RowHeadersWidthSizeMode = _
    DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders

[C#]
// 设定列头的宽度可以自由调整
DataGridView1.ColumnHeadersHeightSizeMode =
    DataGridViewColumnHeadersHeightSizeMode.AutoSize;

// 设定行头的宽度可以自由调整
DataGridView1.RowHeadersWidthSizeMode =
    DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;


4
随时自动调整
a
临时的,让列宽自动调整,这和指定AutoSizeColumnsMode属性一样。

[VB.NET]
' DataGridView1 的所有列宽自动调整一下。
DataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)

' DataGridView1 的第一列的列宽自动调整一下。
DataGridView1.AutoResizeColumn(0, DataGridViewAutoSizeColumnMode.AllCells)

[C#]
// DataGridView1 的所有列宽自动调整一下。
DataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);

// DataGridView1 的第一列的列宽自动调整一下。
DataGridView1.AutoResizeColumn(0, DataGridViewAutoSizeColumnMode.AllCells);

上面调用的 AutoResizeColumns AutoResizeColumn 当指定的是DataGridViewAutoSizeColumnMode.AllCells 的时候,参数可以省略。即:
DataGridView1.AutoResizeColumn(0)
DataGridView1.AutoResizeColumns()

b
,临时的,让行高自动调整

[VB.NET]
' DataGridView1 的所有行高自动调整一下。
DataGridView1.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCells)

' DataGridView1 的第一行的行高自动调整一下。
DataGridView1.AutoResizeRow(0, DataGridViewAutoSizeRowMode.AllCells)

[C#]
// DataGridView1 的所有行高自动调整一下。
DataGridView1.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCells);

// DataGridView1 的第一行的行高自动调整一下。
DataGridView1.AutoResizeRow(0, DataGridViewAutoSizeRowMode.AllCells);

上面调用的 AutoResizeRows AutoResizeRow 当指定的是DataGridViewAutoSizeRowMode.AllCells 的时候,参数可以省略。即:DataGridView1.AutoResizeRow (0) DataGridView1.AutoResizeRows()

c
,临时的,让行头和列头自动调整

[VB.NET]
' 列头高度自动调整
DataGridView1.AutoResizeColumnHeadersHeight()

' 行头宽度自动调整
DataGridView1.AutoResizeRowHeadersWidth( _
    DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)

[C#]
// 列头高度自动调整
DataGridView1.AutoResizeColumnHeadersHeight();

// 行头宽度自动调整
DataGridView1.AutoResizeRowHeadersWidth(
    DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders);


关于性能:
通过 AutoSizeColumnsMode 或者 AutoSizeRowsMode 属性所指定的单元格进行自动调整时,如果调整次数过于多那么将可能导致性能下降,尤其是在行和列数比较多的情况下。在这时用 DisplayedCells 代替 AllCells 能减少非所见的单元格的调整,从而提高性能。


DataGridView 冻结列或行

GO TO TOP

1列冻结
DataGridViewColumn.Frozen
属性为 True 时,该列左侧的所有列被固定,横向滚动时固定列不随滚动条滚动而左右移动。这对于重要列固定显示很有用。

[VB.NET]
' DataGridView1的左侧2列固定
DataGridView1.Columns(1).Frozen = True

[C#]
// DataGridView1的左侧2列固定
DataGridView1.Columns[1].Frozen = true;

但是,DataGridView.AllowUserToOrderColumns = True 时,固定列不能移动到非固定列,反之亦然。

2行冻结
DataGridViewRow.Frozen
属性为 True 时,该行上面的所有行被固定,纵向滚动时固定行不随滚动条滚动而上下移动。

[VB.NET]
' DataGridView1 的上3行固定
DataGridView1.Rows(2).Frozen = True

[C#]
// DataGridView1 的上3行固定
DataGridView1.Rows[2].Frozen = true;


DataGridView 列顺序的调整

GO TO TOP

设定 DataGridView AllowUserToOrderColumns True 的时候,用户可以自由调整列的顺序。
当用户改变列的顺序的时候,其本身的 Index 不会改变,但是 DisplayIndex 改变了。你也可以通过程序改变 DisplayIndex 来改变列的顺序。列顺序发生改变时会引发 ColumnDisplayIndexChanged 事件:

[VB.NET]
' DataGridView1ColumnDisplayIndexChanged事件处理方法
Private Sub DataGridView1_ColumnDisplayIndexChanged(ByVal sender As Object, _
        
ByVal e As DataGridViewColumnEventArgs) _
        
Handles DataGridView1.ColumnDisplayIndexChanged
    Console.WriteLine("{0}
的位置改变到 {1} ", _
        e.Column.Name, e.Column.DisplayIndex)
End Sub

[C#]
// DataGridView1ColumnDisplayIndexChanged事件处理方法
private void DataGridView1_ColumnDisplayIndexChanged(object sender,
    DataGridViewColumnEventArgs e)
{
    Console.WriteLine("{0}
的位置改变到 {1} ",
        e.Column.Name, e.Column.DisplayIndex);
}


DataGridView 行头列头的单元格

GO TO TOP

[VB.NET]
' DataGridView1的第一列列头内容
DataGridView1.Columns(0).HeaderCell.Value = "第一列"

' DataGridView1的第一行行头内容
DataGridView1.Rows(0).HeaderCell.Value = "第一行"

' DataGridView1的左上头部单元内容
DataGridView1.TopLeftHeaderCell.Value = "左上"

[C#]
// 改变DataGridView1的第一列列头内容
DataGridView1.Columns[0].HeaderCell.Value = "第一列";

// 改变DataGridView1的第一行行头内容
DataGridView1.Rows[0].HeaderCell.Value = "第一行";

// 改变DataGridView1的左上头部单元内容
DataGridView1.TopLeftHeaderCell.Value = "左上";


另外你也可以通过 HeaderText 来改变他们的内容。

[VB.NET]
' 改变DataGridView1的第一列列头内容
DataGridView1.Columns(0).HeaderText = "第一列"

[C#]
// 改变DataGridView1的第一列列头内容
DataGridView1.Columns[0].HeaderText = "第一列";


DataGridView 剪切板的操作

GO TO TOP

DataGridView.ClipboardCopyMode 属性被设定为 DataGridViewClipboardCopyMode.Disable 以外的情况时,「Ctrl + C按下的时候,被选择的单元格的内容会拷贝到系统剪切板内。格式有: Text UnicodeTextHtml CommaSeparatedValue。可以直接粘贴到 Excel 内。

ClipboardCopyMode
还可以设定 Header部分是否拷贝: EnableAlwaysIncludeHeaderText 拷贝Header部分、EnableWithoutHeaderText 则不拷贝。默认是 EnableWithAutoHeaderText Header 如果选择了的话,就拷贝。

1
编程方式实现剪切板的拷贝

Clipboard.SetDataObject(DataGridView1.GetClipboardContent())

2) DataGridView
的数据粘贴

实现剪切板的拷贝比较容易,但是实现 DataGridView 的直接粘贴就比较难了。「Ctrl + V」按下进行粘贴时,DataGridView 没有提供方法,只能自己实现。

以下,是粘贴时简单的事例代码,将拷贝数据粘贴到以选择单元格开始的区域内。

[VB.NET]
' 当前单元格是否选择的判断
If DataGridView1.CurrentCell Is Nothing Then
    
Return
End If
Dim insertRowIndex As Integer = DataGridView1.CurrentCell.RowIndex

' 获取剪切板的内容,并按行分割
Dim pasteText As String = Clipboard.GetText()
If String.IsNullOrEmpty(pasteText) Then
    
Return
End If
pasteText = pasteText.Replace(vbCrLf, vbLf)
pasteText = pasteText.Replace(vbCr, vbLf)
pasteText.TrimEnd(
New Char() {vbLf})
Dim lines As String() = pasteText.Split(vbLf)

Dim isHeader As Boolean = True
For Each line As String In lines
    
' 是否是列头
    If isHeader Then
        isHeader = 
False
    
Else
        
' Tab 分割数据
        Dim vals As String() = line.Split(ControlChars.Tab)
        
' 判断列数是否统一
        If vals.Length - 1 <> DataGridView1.ColumnCount Then
            
Throw New ApplicationException("粘贴的列数不正确。")
        
End If
        
Dim row As DataGridViewRow = DataGridView1.Rows(insertRowIndex)
        
' 行头设定
        row.HeaderCell.Value = vals(0)
        
' 单元格内容设定
        Dim i As Integer
        
For i = 0 To row.Cells.Count - 1
            row.Cells(i).Value = vals((i + 1))
        
Next i

        
' DataGridView的行索引+1
        insertRowIndex += 1
    
End If
Next line

[C#]
//当前单元格是否选择的判断
if (DataGridView1.CurrentCell == null)
    
return;
int insertRowIndex = DataGridView1.CurrentCell.RowIndex;

// 获取剪切板的内容,并按行分割
string pasteText = Clipboard.GetText();
if (string.IsNullOrEmpty(pasteText))
    
return;
pasteText = pasteText.Replace(" ", " ");
pasteText = pasteText.Replace(' ', ' ');
pasteText.TrimEnd(
new char[] { ' ' });
string[] lines = pasteText.Split(' ');

bool isHeader = true;
foreach (string line in lines)
{
    
// 是否是列头
    if (isHeader)
    {
        isHeader = 
false;
        
continue;
    }

    
// Tab 分割数据
    string[] vals = line.Split(' ');
    
// 判断列数是否统一
    if (vals.Length - 1 != DataGridView1.ColumnCount)
        
throw new ApplicationException("粘贴的列数不正确。");
    DataGridViewRow row = DataGridView1.Rows[insertRowIndex];
    
// 行头设定
    row.HeaderCell.Value = vals[0];
    
// 单元格内容设定
    for (int i = 0; i < row.Cells.Count; i++)
    {
        row.Cells[i].Value = vals[i + 1];
    }

    
//  DataGridView的行索引+1
    insertRowIndex++;
}


DataGridView 单元格的ToolTip的设置

GO TO TOP

DataGridView.ShowCellToolTips = True 的情况下,单元格的 ToolTip 可以表示出来。对于单元格窄小,无法完全显示的单元格, ToolTip 可以显示必要的信息。

1
设定单元格的ToolTip内容

[VB.NET]
' 设定单元格的ToolTip内容
DataGridView1(0, 0).ToolTipText = "该单元格的内容不能修改"

' 设定列头的单元格的ToolTip内容
DataGridView1.Columns(0).ToolTipText = "该列只能输入数字"

' 设定行头的单元格的ToolTip内容
DataGridView1.Rows(0).HeaderCell.ToolTipText = "该行单元格内容不能修改"

[C#]
// 设定单元格的ToolTip内容
DataGridView1[0, 0].ToolTipText = "该单元格的内容不能修改";

// 设定列头的单元格的ToolTip内容
DataGridView1.Columns[0].ToolTipText = "该列只能输入数字";

// 设定行头的单元格的ToolTip内容
DataGridView1.Rows[0].HeaderCell.ToolTipText = "该行单元格内容不能修改";


2
CellToolTipTextNeeded 事件
在批量的单元格的 ToolTip 设定的时候,一个一个指定那么设定的效率比较低,这时候可以利用 CellToolTipTextNeeded 事件。当单元格的 ToolTipText 变化的时候也会引发该事件。但是,当DataGridViewDataSource被指定且VirualMode=True的时候,该事件不会被引发。

[VB.NET]
' CellToolTipTextNeeded事件处理方法
Private Sub DataGridView1_CellToolTipTextNeeded(ByVal sender As Object, _
        
ByVal e As DataGridViewCellToolTipTextNeededEventArgs) _
        
Handles DataGridView1.CellToolTipTextNeeded
    e.ToolTipText = e.ColumnIndex.ToString() + ", " + e.RowIndex.ToString()
End Sub

[C#]
// CellToolTipTextNeeded事件处理方法
private void DataGridView1_CellToolTipTextNeeded(object sender,
    DataGridViewCellToolTipTextNeededEventArgs e)
{
    e.ToolTipText = e.ColumnIndex.ToString() + ", " + e.RowIndex.ToString();
}


DataGridView 的右键菜单(ContextMenuStrip

GO TO TOP

DataGridView, DataGridViewColumn, DataGridViewRow, DataGridViewCell ContextMenuStrip 属性。可以通过设定 ContextMenuStrip 对象来控制 DataGridView 的右键菜单的显示。 DataGridViewColumn ContextMenuStrip 属性设定了除了列头以外的单元格的右键菜单。 DataGridViewRow ContextMenuStrip 属性设定了除了行头以外的单元格的右键菜单。DataGridViewCell   ContextMenuStrip 属性设定了指定单元格的右键菜单。

[VB.NET]
' DataGridView ContextMenuStrip 设定
DataGridView1.ContextMenuStrip = Me.ContextMenuStrip1

' 列的 ContextMenuStrip 设定
DataGridView1.Columns(0).ContextMenuStrip = Me.ContextMenuStrip2
' 列头的 ContextMenuStrip 设定
DataGridView1.Columns(0).HeaderCell.ContextMenuStrip = Me.ContextMenuStrip2

' 行的 ContextMenuStrip 设定
DataGridView1.Rows(0).ContextMenuStrip = Me.ContextMenuStrip3

' 单元格的 ContextMenuStrip 设定
DataGridView1(0, 0).ContextMenuStrip = Me.ContextMenuStrip4

[C#]
// DataGridView ContextMenuStrip 设定
DataGridView1.ContextMenuStrip = this.ContextMenuStrip1;

// 列的 ContextMenuStrip 设定
DataGridView1.Columns[0].ContextMenuStrip = this.ContextMenuStrip2;
// 列头的 ContextMenuStrip 设定
DataGridView1.Columns[0].HeaderCell.ContextMenuStrip = this.ContextMenuStrip2;

// 行的 ContextMenuStrip 设定
DataGridView1.Rows[0].ContextMenuStrip = this.ContextMenuStrip3;

// 单元格的 ContextMenuStrip 设定
DataGridView1[0, 0].ContextMenuStrip = this.ContextMenuStrip4;

对于单元格上的右键菜单的设定,优先顺序是: Cell > Row > Column > DataGridView

CellContextMenuStripNeededRowContextMenuStripNeeded 事件

利用 CellContextMenuStripNeeded 事件可以设定单元格的右键菜单,尤其但需要右键菜单根据单元格值的变化而变化的时候。比起使用循环遍历,使用该事件来设定右键菜单的效率更高。但是,在DataGridView使用了DataSource绑定而且是VirtualMode的时候,该事件将不被引发。

[VB.NET]
' CellContextMenuStripNeeded事件处理方法
Private Sub DataGridView1_CellContextMenuStripNeeded( _
        
ByVal sender As Object, _
        
ByVal e As DataGridViewCellContextMenuStripNeededEventArgs) _
        
Handles DataGridView1.CellContextMenuStripNeeded
    
Dim dgv As DataGridView = CType(sender, DataGridView)
    
If e.RowIndex < 0 Then
        
' 列头的ContextMenuStrip设定
        e.ContextMenuStrip = Me.ContextMenuStrip1
    
ElseIf e.ColumnIndex < 0 Then
        
' 行头的ContextMenuStrip设定
        e.ContextMenuStrip = Me.ContextMenuStrip2
    
ElseIf TypeOf (dgv(e.ColumnIndex, e.RowIndex).Value) Is Integer Then
        
' 如果单元格值是整数时
        e.ContextMenuStrip = Me.ContextMenuStrip3
    
End If
End Sub

[C#]
// CellContextMenuStripNeeded事件处理方法
private void DataGridView1_CellContextMenuStripNeeded(object sender,
    DataGridViewCellContextMenuStripNeededEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;
    
if (e.RowIndex < 0)
    {
        
// 列头的ContextMenuStrip设定
        e.ContextMenuStrip = this.ContextMenuStrip1;
    }
    
else if (e.ColumnIndex < 0)
    {
        
// 行头的ContextMenuStrip设定
        e.ContextMenuStrip = this.ContextMenuStrip2;
    }
    
else if (dgv[e.ColumnIndex, e.RowIndex].Value is int)
    {
        
// 如果单元格值是整数时
        e.ContextMenuStrip = this.ContextMenuStrip3;
    }
}

同样,可以通过 RowContextMenuStripNeeded 事件来设定行的右键菜单。

[VB.NET]
' RowContextMenuStripNeeded事件处理方法
Private Sub DataGridView1_RowContextMenuStripNeeded( _
        
ByVal sender As Object, _
        
ByVal e As DataGridViewRowContextMenuStripNeededEventArgs) _
        
Handles DataGridView1.RowContextMenuStripNeeded
    
Dim dgv As DataGridView = CType(sender, DataGridView)
    
' 当"Column1"列是Bool型且为True时、设定其的ContextMenuStrip
    Dim boolVal As Object = dgv("Column1", e.RowIndex).Value
    Console.WriteLine(boolVal)
    
If TypeOf boolVal Is Boolean AndAlso CBool(boolVal) Then
        e.ContextMenuStrip = 
Me.ContextMenuStrip1
    
End If
End Sub

[C#]
// RowContextMenuStripNeeded事件处理方法
private void DataGridView1_RowContextMenuStripNeeded(object sender,
    DataGridViewRowContextMenuStripNeededEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;
    
// 当"Column1"列是Bool型且为True时、设定其的ContextMenuStrip
    object boolVal = dgv["Column1", e.RowIndex].Value;
    Console.WriteLine(boolVal);
    
if (boolVal is bool && (bool)boolVal)
    {
        e.ContextMenuStrip = 
this.ContextMenuStrip1;
    }
}


CellContextMenuStripNeeded
 事件处理方法的参数中、「e.ColumnIndex=-1」表示行头、「e.RowIndex=-1」表示列头。RowContextMenuStripNeeded则不存在「e.RowIndex=-1」的情况。


DataGridView 的单元格的边框、网格线样式的设定

GO TO TOP

1) DataGridView 的边框线样式的设定
DataGridView
的边框线的样式是通过 DataGridView.BorderStyle 属性来设定的。 BorderStyle 属性设定值是一个
BorderStyle
枚举: FixedSingle(单线,默认)、Fixed3DNone

2)
单元格的边框线样式的设定

单元格的边框线的样式是通过 DataGridView.CellBorderStyle 属性来设定的。 CellBorderStyle 属性设定值是
DataGridViewCellBorderStyle
枚举。(详细参见 MSDN
另外,通过 DataGridView.ColumnHeadersBorderStyle RowHeadersBorderStyle 属性可以修改 DataGridView 的头部的单元格边框线样式。属性设定值是 DataGridViewHeaderBorderStyle 枚举。(详细参见 MSDN

3
单元格的边框颜色的设定
单元格的边框线的颜色可以通过 DataGridView.GridColor 属性来设定的。默认是 ControlDarkDark 。但是只有在 CellBorderStyle 被设定为 SingleSingleHorizontalSingleVertical  的条件下才能改变其边框线的颜色。同样,ColumnHeadersBorderStyle 以及 RowHeadersBorderStyle 只有在被设定为 Single 时,才能改变颜色。

4
单元格的上下左右的边框线式样的单独设定
CellBorderStyle
只能设定单元格全部边框线的式样。要单独改变单元格某一边边框式样的话,需要用到DataGridView.AdvancedCellBorderStyle属性。如示例:

[VB.NET]
' 单元格的上边和左边线设为二重线
'
单元格的下边和右边线设为单重线
DataGridView1.AdvancedCellBorderStyle.Top = _
    DataGridViewAdvancedCellBorderStyle.InsetDouble
DataGridView1.AdvancedCellBorderStyle.Right = _
    DataGridViewAdvancedCellBorderStyle.Inset
DataGridView1.AdvancedCellBorderStyle.Bottom = _
    DataGridViewAdvancedCellBorderStyle.Inset
DataGridView1.AdvancedCellBorderStyle.Left = _
    DataGridViewAdvancedCellBorderStyle.InsetDouble


同样,设定行头单元格的属性是: AdvancedRowHeadersBorderStyle设定列头单元格属性是:AdvancedColumnHeadersBorderStyle


DataGridView 单元格表示值的自定义

GO TO TOP

通过CellFormatting事件,可以自定义单元格的表示值。(比如:值为Error的时候,单元格被设定为红色)
下面的示例:将“Colmn1”列的值改为大写。

[VB.NET]
'CellFormatting 事件处理方法
Private Sub DataGridView1_CellFormatting(ByVal sender As Object, _
        
ByVal e As DataGridViewCellFormattingEventArgs) _
        
Handles DataGridView1.CellFormatting
    
Dim dgv As DataGridView = CType(sender, DataGridView)

    
如果单元格是“Column1”列的单元格
    If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _
            
TypeOf e.Value Is String Then
        
将单元格值改为大写
        Dim str As String = e.Value.ToString()
        e.Value = 
str.ToUpper()
        
应用该FormatFormat完毕。
        e.FormattingApplied = True
    
End If
End Sub

[C#]
//CellFormatting 事件处理方法
private void DataGridView1_CellFormatting(object sender,
    DataGridViewCellFormattingEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;

    
// 如果单元格是“Column1”列的单元格
    if (dgv.Columns[e.ColumnIndex].Name == "Column1" && e.Value is string)
    {
        
// 将单元格值改为大写
        string str = e.Value.ToString();
        e.Value = str.ToUpper();
        
// 应用该FormatFormat完毕。
        e.FormattingApplied = true;
    }
}


CellFormatting
事件的DataGridViewCellFormattingEventArgs对象的Value属性一开始保存着未被格式化的值。当Value属性被设定表示用的文本之后,把FormattingApplied属性做为True,告知DataGridView文本已经格式化完毕。如果不这样做的话,DataGridView会根据已经设定的FormatNullValueDataSourceNullValueFormatProvider属性会将Value属性会被重新格式化一遍。


DataGridView 用户输入时,单元格输入值的设定

GO TO TOP

通过 DataGridView.CellParsing 事件可以设定用户输入的值。下面的示例:当输入英文文本内容的时候,立即被改变为大写。

[VB.NET]
'CellParsing 事件处理方法
Private Sub DataGridView1_CellParsing(ByVal sender As Object, _
        
ByVal e As DataGridViewCellParsingEventArgs) _
        
Handles DataGridView1.CellParsing
    
Dim dgv As DataGridView = CType(sender, DataGridView)

    
' 单元格列为“Column1”
    If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _
            e.DesiredType 
Is GetType(StringThen
        
' 将单元格值设为大写
        e.Value = e.Value.ToString().ToUpper()
        
' 解析完毕
        e.ParsingApplied = True
    
End If
End Sub

[C#]
//CellParsing 事件处理方法
private void DataGridView1_CellParsing(object sender,
    DataGridViewCellParsingEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;

    
//单元格列为“Column1”
    if (dgv.Columns[e.ColumnIndex].Name == "Column1" &&
        e.DesiredType == 
typeof(string))
    {
        
//将单元格值设为大写
        e.Value = e.Value.ToString().ToUpper();
        
//解析完毕
        e.ParsingApplied = true;
    }
}


DataGridView 新加行的默认值的设定

GO TO TOP


需要指定新加行的默认值的时候,可以在DataGridView.DefaultValuesNeeded事件里处理。在该事件中处理除了可以设定默认值以外,还可以指定某些特定的单元格的ReadOnly属性等。

[VB.NET]
' DefaultValuesNeeded 事件处理方法
Private Sub DataGridView1_DefaultValuesNeeded(ByVal sender As Object, _
        
ByVal e As DataGridViewRowEventArgs) _
        
Handles DataGridView1.DefaultValuesNeeded
    
设定单元格默认值
    e.Row.Cells("Column1").Value = 0
    e.Row.Cells("Column2").Value = "-"
End Sub

[C#]
// DefaultValuesNeeded 事件处理方法
private void DataGridView1_DefaultValuesNeeded(object sender,
    DataGridViewRowEventArgs e)
{
    
// 设定单元格的默认值
    e.Row.Cells["Column1"].Value = 0;
    e.Row.Cells["Column2"].Value = "-";
}


本章结束

 DataGridView新特色、常用操作

1、自定义列
Customize Cells and Columns in the Windows Forms DataGridView Control by Extending Their 
    Behavior and Appearance 
    Host Controls in Windows Forms DataGridView Cells 
    
继承 DataGridViewTextBoxCell 类生成新的Cell类,然后再继承 DataGridViewColumn 生成新的Column类,并指定
    CellTemplate
为新的Cell类。新生成的Column便可以增加到DataGridView中去。
2
、自动适应列宽
Programmatically Resize Cells to Fit Content in the Windows Forms DataGridView Control 
    Samples

DataGridView.AutoSizeColumns(       DataGridViewAutoSizeColumnCriteria.HeaderAndDisplayedRows);DataGridView.AutoSizeColumn(            DataGridViewAutoSizeColumnCriteria.HeaderOnly,            2, false);DataGridView.AutoSizeRow(            DataGridViewAutoSizeRowCriteria.Columns,            2, false);DataGridView.AutoSizeRows(          DataGridViewAutoSizeRowCriteria.HeaderAndColumns,            0, dataGridView1.Rows.Count, false);

3、可以绑定并显示对象
    Bind Objects to Windows Forms DataGridView Controls 
4
、可以改变表格线条风格
    Change the Border and Gridline Styles in the Windows Forms DataGridView Control 
    Samples:

this.dataGridView1.GridColor = Color.BlueViolet;this.dataGridView1.BorderStyle = BorderStyle.Fixed3D;this.dataGridView1.CellBorderStyle = DataGridViewCellBorderStyle.None;this.dataGridView1.RowHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;this.dataGridView1.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;

5、动态改变列是否显示,和动态改变列的显示顺序
    Change the Order of the Columns in the Windows Forms DataGridView Control 
    Samples

customersDataGridView.Columns["CustomerID"].Visible = false;customersDataGridView.Columns["ContactName"].DisplayIndex = 0;customersDataGridView.Columns["ContactTitle"].DisplayIndex = 1;customersDataGridView.Columns["City"].DisplayIndex = 2;customersDataGridView.Columns["Country"].DisplayIndex = 3;customersDataGridView.Columns["CompanyName"].DisplayIndex = 4;

6、可以在列中显示图像
    Display Images in Cells of the Windows Forms DataGridView Control 
    Samples

Icon treeIcon = new Icon(this.GetType(), "tree.ico");DataGridViewImageColumn iconColumn = new DataGridViewImageColumn();iconColumn.Image = treeIcon.ToBitmap();iconColumn.Name = "Tree";iconColumn.HeaderText = "Nice tree";dataGridView1.Columns.Insert(2, iconColumn);

7、格式化显示内容:
    Format Data in the Windows Forms DataGridView Control 
    Samples:

this.dataGridView1.Columns["UnitPrice"].DefaultCellStyle.Format = "c";this.dataGridView1.Columns["ShipDate"].DefaultCellStyle.Format = "d";this.dataGridView1.DefaultCellStyle.NullValue = "no entry";this.dataGridView1.DefaultCellStyle.WrapMode = DataGridViewWrapMode.Wrap;this.dataGridView1.Columns["CustomerName"].DefaultCellStyle.Alignment =                     DataGridViewContentAlignment.MiddleRight;

8、在拖动列的滚动条时可以将指定的列冻结
    Freeze Columns in the Windows Forms DataGridView Control 
    Samples
:将指定列及以前的列固定不动

this.dataGridView1.Columns["AddToCartButton"].Frozen = true;

9、获取选择的单元格,,
    Get the Selected Cells, Rows, and Columns in the Windows Forms DataGridView Control 
    Samples:
       
msdn
10
、显示录入时出现的错误信息
    Handle Errors that Occur During Data Entry in the Windows Forms DataGridView Control 
    Samples

private void dataGridView1_DataError(object sender,    DataGridViewDataErrorEventArgs e){    // If the data source raises an exception when a cell value is     // commited, display an error message.    if (e.Exception != null &&        e.Context == DataGridViewDataErrorContext.Commit)    {        MessageBox.Show("CustomerID value must be unique.");    }}

11、大数据量显示采用Virtual Mode 
    Implement Virtual Mode in the Windows Forms DataGridView Control 
12
、设置指定的列只读
    Make Columns in the Windows Forms DataGridView Control Read-Only 
    Samples

dataGridView1.Columns["CompanyName"].ReadOnly = true;

13
、移去自动生成的列
    Remove Autogenerated Columns from a Windows Forms DataGridView Control 
    Sample:

dataGridView1.AutoGenerateColumns = true;dataGridView1.DataSource = customerDataSet;dataGridView1.Columns.Remove("Fax");
或:

dataGridView1.Columns["CustomerID"].Visible = false;
14
、自定义选择模式
    Set the Selection Mode of the Windows Forms DataGridView Control 
    Sample

this.dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;this.dataGridView1.MultiSelect = false;

15、自定义设定光标进入单元格是否编辑模式(编辑模式)
    Specify the Edit Mode for the Windows Forms DataGridView Control

this.dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
16
、新行指定默认值
    Specify Default Values for New Rows in the Windows Forms DataGridView Control 
    Sample

private void dataGridView1_DefaultValuesNeeded(object sender,     System.Windows.Forms.DataGridViewRowEventArgs e){    e.Row.Cells["Region"].Value = "WA";    e.Row.Cells["City"].Value = "Redmond";    e.Row.Cells["PostalCode"].Value = "98052-6399";    e.Row.Cells["Region"].Value = "NA";    e.Row.Cells["Country"].Value = "USA";    e.Row.Cells["CustomerID"].Value = NewCustomerId();}

17、数据验证
    Validate Data in the Windows Forms DataGridView Control 
    Samples

private void dataGridView1_CellValidating(object sender,           DataGridViewCellValidatingEventArgs e){    // Validate the CompanyName entry by disallowing empty strings.    if (dataGridView1.Columns[e.ColumnIndex].Name == "CompanyName")    {        if (e.FormattedValue.ToString() == String.Empty)        {            dataGridView1.Rows[e.RowIndex].ErrorText =                "Company Name must not be empty";            e.Cancel = true;        }    }}

posted @ 2007-09-07 17:34  四两  阅读(8140)  评论(0编辑  收藏  举报
加油,哥们,现在开始!