DataGridView 所有数据绑定方式详解 (VB.NET, VS2010) DataGridView 提供了多种数据绑定方式,以下是完整的绑定方法分类和详细说明: 一、基本数据绑定方式 1. 绑定 DataTable
' 创建DataTable
Dim dt As New DataTable("Products")
dt.Columns.Add("ID", GetType(Integer))
dt.Columns.Add("Name", GetType(String))
dt.Columns.Add("Price", GetType(Decimal))
' 添加数据
dt.Rows.Add(1, "笔记本电脑", 5999.99)
dt.Rows.Add(2, "智能手机", 2999.99)
' 直接绑定
dgv.DataSource = dt
' 优点:简单直接,自动生成列
' 缺点:列顺序和格式控制较弱
2. 绑定 DataView
' 从DataTable创建DataView
Dim dv As New DataView(dt)
' 设置过滤和排序
dv.RowFilter = "Price > 2000"
dv.Sort = "Price DESC"
' 绑定DataView
dgv.DataSource = dv
' 优点:支持过滤和排序
' 缺点:需要先有DataTable
3. 绑定 DataSet
' 创建DataSet并添加多个DataTable
Dim ds As New DataSet("Inventory")
ds.Tables.Add(dt) ' 添加前面创建的Products表
ds.Tables.Add(New DataTable("Categories")) ' 添加另一个表
' 绑定指定表
dgv.DataSource = ds
dgv.DataMember = "Products"
' 优点:适合多表数据
' 缺点:稍复杂
4. 绑定 List(Of T)
' 定义实体类
Public Class Product
Public Property ID As Integer
Public Property Name As String
Public Property Price As Decimal
End Class
' 创建列表
Dim products As New List(Of Product)()
products.Add(New Product With {.ID = 1, .Name = "笔记本电脑", .Price = 5999.99})
products.Add(New Product With {.ID = 2, .Name = "智能手机", .Price = 2999.99})
' 绑定列表
dgv.DataSource = products
' 优点:强类型,面向对象
' 缺点:需要自定义列时需设置AutoGenerateColumns=False
5. 绑定数组
' 创建对象数组
Dim productsArray As Object() = {
New With {.ID = 1, .Name = "笔记本电脑", .Price = 5999.99},
New With {.ID = 2, .Name = "智能手机", .Price = 2999.99}
}
' 绑定数组
dgv.DataSource = productsArray
' 优点:简单快速
' 缺点:匿名类型,后期维护困难
二、高级数据绑定方式 1. 使用 BindingSource 中间层
' 创建BindingSource
Dim bs As New BindingSource()
' 设置数据源
bs.DataSource = products ' 可以是List/DataTable等
' 绑定到DataGridView
dgv.DataSource = bs
' 数据操作通过BindingSource
bs.Add(New Product With {.ID = 3, .Name = "平板电脑", .Price = 1999.99})
bs.RemoveAt(0)
' 优点:解耦数据源和控件,支持更多功能
' 缺点:增加一层间接性
2. 自定义对象绑定 (实现 ITypedList/IListSource)
' 自定义集合类实现ITypedList
Public Class ProductCollection
Implements ITypedList, IList
Private _products As New List(Of Product)()
' 实现必要接口方法...
Public Function GetItemProperties(properties As PropertyDescriptorCollection) As PropertyDescriptorCollection _
Implements ITypedList.GetItemProperties
Return TypeDescriptor.GetProperties(GetType(Product))
End Function
' 其他方法...
End Class
' 使用自定义集合
Dim customProducts As New ProductCollection()
customProducts.Add(New Product With {.ID = 1, .Name = "笔记本电脑", .Price = 5999.99})
' 绑定
dgv.DataSource = customProducts
' 优点:完全控制数据绑定行为
' 缺点:实现复杂
3. 虚拟模式绑定 (超大数据集)
' 启用虚拟模式
dgv.VirtualMode = True
dgv.RowCount = 1000000 ' 设置总行数
' 处理数据获取事件
Private Sub dgv_CellValueNeeded(sender As Object, e As DataGridViewCellValueEventArgs)
' 根据需要从数据库或其他源获取数据
e.Value = GetDataFromDatabase(e.RowIndex, e.ColumnIndex)
End Sub
' 处理数据更新事件
Private Sub dgv_CellValuePushed(sender As Object, e As DataGridViewCellValueEventArgs)
UpdateDataInDatabase(e.RowIndex, e.ColumnIndex, e.Value)
End Sub
' 优点:处理超大数据集
' 缺点:实现复杂,需要手动管理数据
4. 分层数据绑定 (主从表)
' 主表DataGridView
dgvMaster.DataSource = ds
dgvMaster.DataMember = "Departments"
' 从表DataGridView
dgvDetail.DataSource = ds
dgvDetail.DataMember = "Departments.DepartmentEmployees"
' 或者使用BindingSource建立关系
Dim bsDept As New BindingSource(ds, "Departments")
Dim bsEmp As New BindingSource(bsDept, "DepartmentEmployees")
dgvMaster.DataSource = bsDept
dgvDetail.DataSource = bsEmp
' 优点:显示关联数据
' 缺点:需要正确设置数据关系
三、自定义列绑定方法 1. 手动添加列并绑定
' 禁止自动生成列
dgv.AutoGenerateColumns = False
' 手动添加列
Dim colID As New DataGridViewTextBoxColumn()
colID.Name = "colID"
colID.DataPropertyName = "ID" ' 绑定到数据源的ID属性
colID.HeaderText = "产品ID"
dgv.Columns.Add(colID)
Dim colName As New DataGridViewTextBoxColumn()
colName.Name = "colName"
colName.DataPropertyName = "Name"
colName.HeaderText = "产品名称"
dgv.Columns.Add(colName)
' 绑定数据
dgv.DataSource = products
' 优点:完全控制列显示
' 缺点:需要手动设置每列
2. 自定义列类型绑定
' 添加图像列
Dim imgCol As New DataGridViewImageColumn()
imgCol.Name = "colImage"
imgCol.DataPropertyName = "ImageData" ' 绑定到字节数组或Image类型属性
imgCol.ImageLayout = DataGridViewImageCellLayout.Zoom
dgv.Columns.Add(imgCol)
' 添加按钮列
Dim btnCol As New DataGridViewButtonColumn()
btnCol.Name = "colAction"
btnCol.HeaderText = "操作"
btnCol.Text = "查看"
btnCol.UseColumnTextForButtonValue = True
dgv.Columns.Add(btnCol)
' 添加组合框列
Dim cmbCol As New DataGridViewComboBoxColumn()
cmbCol.Name = "colCategory"
cmbCol.DataPropertyName = "CategoryID" ' 绑定到值字段
cmbCol.DisplayMember = "CategoryName" ' 显示文本字段
cmbCol.ValueMember = "CategoryID" ' 值字段
cmbCol.DataSource = GetCategories() ' 数据源
dgv.Columns.Add(cmbCol)
3. 动态列绑定
' 根据运行时条件创建列
Public Sub BindDataWithDynamicColumns(data As Object, Optional includeColumns As String() = Nothing)
dgv.Columns.Clear()
' 获取数据类型的属性
Dim props As PropertyDescriptorCollection = TypeDescriptor.GetProperties(data.GetType().GetGenericArguments()(0))
For Each prop As PropertyDescriptor In props
' 如果指定了包含列且当前列不在其中,则跳过
If includeColumns IsNot Nothing AndAlso Not includeColumns.Contains(prop.Name) Then
Continue For
End If
' 根据属性类型创建不同列
If prop.PropertyType Is GetType(Boolean) Then
Dim col As New DataGridViewCheckBoxColumn()
col.Name = "col" & prop.Name
col.DataPropertyName = prop.Name
col.HeaderText = prop.Name
dgv.Columns.Add(col)
ElseIf prop.PropertyType Is GetType(DateTime) Then
Dim col As New DataGridViewTextBoxColumn()
col.Name = "col" & prop.Name
col.DataPropertyName = prop.Name
col.HeaderText = prop.Name
col.DefaultCellStyle.Format = "yyyy-MM-dd"
dgv.Columns.Add(col)
Else
Dim col As New DataGridViewTextBoxColumn()
col.Name = "col" & prop.Name
col.DataPropertyName = prop.Name
col.HeaderText = prop.Name
dgv.Columns.Add(col)
End If
Next
' 绑定数据
dgv.DataSource = data
End Sub
' 使用示例
BindDataWithDynamicColumns(products, {"ID", "Name", "Price"})
四、数据绑定最佳实践 1. 性能优化绑定
' 大数据量绑定优化
Public Sub BindLargeData(data As IList)
' 禁用自动操作
dgv.SuspendLayout()
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None
dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None
' 使用BindingSource
Dim bs As New BindingSource()
bs.DataSource = data
dgv.DataSource = bs
' 恢复自动操作
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells
dgv.ResumeLayout()
End Sub
2. 双向数据绑定
' 设置双向绑定
Public Sub SetupTwoWayBinding()
' 使用BindingSource
Dim bs As New BindingSource()
bs.DataSource = GetProducts()
dgv.DataSource = bs
' 手动列设置
dgv.AutoGenerateColumns = False
' ID列 (只读)
Dim colID As New DataGridViewTextBoxColumn()
colID.DataPropertyName = "ID"
colID.ReadOnly = True
dgv.Columns.Add(colID)
' 可编辑列
Dim colName As New DataGridViewTextBoxColumn()
colName.DataPropertyName = "Name"
colName.ReadOnly = False
dgv.Columns.Add(colName)
' 保存按钮
Dim btnSave As New DataGridViewButtonColumn()
btnSave.Text = "保存"
btnSave.UseColumnTextForButtonValue = True
dgv.Columns.Add(btnSave)
' 处理单元格值变化
AddHandler dgv.CellValueChanged, AddressOf dgv_CellValueChanged
AddHandler dgv.CellContentClick, AddressOf dgv_CellContentClick
End Sub
Private Sub dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs)
' 自动更新数据源
Dim bs As BindingSource = CType(dgv.DataSource, BindingSource)
bs.EndEdit()
End Sub
Private Sub dgv_CellContentClick(sender As Object, e As DataGridViewCellEventArgs)
If e.ColumnIndex = dgv.Columns("btnSave").Index Then
SaveChanges()
End If
End Sub
Private Sub SaveChanges()
Dim bs As BindingSource = CType(dgv.DataSource, BindingSource)
Dim products As List(Of Product) = CType(bs.DataSource, List(Of Product))
' 保存到数据库
Using db As New DbContext()
For Each product In products
db.UpdateProduct(product)
Next
db.SaveChanges()
End Using
MessageBox.Show("保存成功!")
End Sub
3. 数据验证绑定
' 设置数据验证
Public Sub SetupDataValidation()
dgv.DataSource = GetProducts()
' 处理数据验证事件
AddHandler dgv.DataError, AddressOf dgv_DataError
AddHandler dgv.CellValidating, AddressOf dgv_CellValidating
End Sub
Private Sub dgv_DataError(sender As Object, e As DataGridViewDataErrorEventArgs)
MessageBox.Show($"数据错误: {e.Exception.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Sub
Private Sub dgv_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs)
If dgv.Columns(e.ColumnIndex).Name = "colPrice" Then
If Not Decimal.TryParse(e.FormattedValue.ToString(), Nothing) Then
e.Cancel = True
MessageBox.Show("价格必须是有效数字", "验证错误", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
End If
End Sub
五、特殊数据源绑定 1. 绑定 XML 数据
' 从XML文件加载数据
Public Sub BindXmlData(xmlFile As String)
Dim ds As New DataSet()
ds.ReadXml(xmlFile)
dgv.DataSource = ds
dgv.DataMember = ds.Tables(0).TableName
End Sub
2. 绑定 JSON 数据
' 使用Json.NET绑定JSON数据
Public Sub BindJsonData(jsonString As String)
Dim products = JsonConvert.DeserializeObject(Of List(Of Product))(jsonString)
dgv.DataSource = products
End Sub
3. 绑定数据库存储过程结果
' 绑定存储过程结果
Public Sub BindStoredProcedureResults()
Using conn As New SqlConnection(connectionString)
Using cmd As New SqlCommand("usp_GetProducts", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@CategoryID", 1)
Dim adapter As New SqlDataAdapter(cmd)
Dim dt As New DataTable()
adapter.Fill(dt)
dgv.DataSource = dt
End Using
End Using
End Sub
六、数据绑定事件处理 完整事件处理示例
Public Sub SetupDataGridWithEvents()
' 绑定数据
dgv.DataSource = GetProducts()
' 添加事件处理
AddHandler dgv.DataBindingComplete, AddressOf dgv_DataBindingComplete
AddHandler dgv.CellBeginEdit, AddressOf dgv_CellBeginEdit
AddHandler dgv.CellEndEdit, AddressOf dgv_CellEndEdit
AddHandler dgv.CellValueChanged, AddressOf dgv_CellValueChanged
AddHandler dgv.RowEnter, AddressOf dgv_RowEnter
AddHandler dgv.RowValidating, AddressOf dgv_RowValidating
AddHandler dgv.Sorted, AddressOf dgv_Sorted
End Sub
Private Sub dgv_DataBindingComplete(sender As Object, e As DataGridViewBindingCompleteEventArgs)
' 数据绑定完成后自动调整列宽
dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)
' 设置行号
For i As Integer = 0 To dgv.Rows.Count - 1
dgv.Rows(i).HeaderCell.Value = (i + 1).ToString()
Next
End Sub
Private Sub dgv_CellBeginEdit(sender As Object, e As DataGridViewCellCancelEventArgs)
' 记录编辑前的值
If e.RowIndex >= 0 AndAlso e.ColumnIndex >= 0 Then
Dim oldValue = dgv.Rows(e.RowIndex).Cells(e.ColumnIndex).Value
' 可以保存到某个变量用于撤销操作
End If
End Sub
Private Sub dgv_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs)
' 验证编辑后的值
If dgv.Columns(e.ColumnIndex).Name = "Price" Then
Dim newValue As Decimal
If Not Decimal.TryParse(dgv.Rows(e.RowIndex).Cells(e.ColumnIndex).Value.ToString(), newValue) OrElse newValue < 0 Then
dgv.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = 0
MessageBox.Show("价格必须是非负数字", "输入错误", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
End If
End Sub
Private Sub dgv_RowValidating(sender As Object, e As DataGridViewCellCancelEventArgs)
' 行级验证
Dim row As DataGridViewRow = dgv.Rows(e.RowIndex]
If String.IsNullOrEmpty(row.Cells("Name").Value.ToString()) Then
e.Cancel = True
MessageBox.Show("产品名称不能为空", "验证错误", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
End Sub
Private Sub dgv_Sorted(sender As Object, e As EventArgs)
' 排序后更新行号
For i As Integer = 0 To dgv.Rows.Count - 1
dgv.Rows(i).HeaderCell.Value = (i + 1).ToString()
Next
End Sub
以上涵盖了DataGridView的所有主要数据绑定方式,从简单的DataTable绑定到复杂的自定义绑定和虚拟模式绑定。
根据项目需求选择最适合的绑定方式,并考虑性能、可维护性和用户体验等因素。
