7.1.6 处理单元格事件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Sub DataGridView1_CellValidating(ByVal sender As Object,
ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs
) Handles DataGridView1.CellValidating
Debug.WriteLine("Cell Validating: " & e.RowIndex & ", " & e.ColumnIndex)
If e.ColumnIndex = 1 AndAlso
e.FormattedValue.ToString.Trim.Length = 0 Then
e.Cancel = True
End If
End Sub
7.1.7.5 使用DataGridViewImageColumn对象
用上下文菜单向ImageCell中插入图像
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Dim currentPhotoCell As DataGridViewImageCell
Sub InsertPhotoFromFileToolStripMenuItem_Click(ByVal sender As Object, _
ByVal e As EventArgs _
) Handles InsertPhotoFromFileToolStripMenuItem.Click
Dim dlg As New OpenFileDialog
dlg.Multiselect = False
dlg.Filter = "GIF|*.gif|BMP|*.bmp|JPEG|*.jpg;*.jpeg|All Files|*.*"
dlg.FilterIndex = 3
dlg.Title = "select a photo to insert"
If dlg.ShowDialog <> Windows.Forms.DialogResult.OK Then Return
Dim bmp As New Bitmap(dlg.FileName)
currentPhotoCell.Value = bmp
End Sub
Sub InsertPhotoFromFileToolStripMenuItem_Click(ByVal sender As Object, _
ByVal e As EventArgs _
) Handles InsertPhotoFromFileToolStripMenuItem.Click
Dim dlg As New OpenFileDialog
dlg.Multiselect = False
dlg.Filter = "GIF|*.gif|BMP|*.bmp|JPEG|*.jpg;*.jpeg|All Files|*.*"
dlg.FilterIndex = 3
dlg.Title = "select a photo to insert"
If dlg.ShowDialog <> Windows.Forms.DialogResult.OK Then Return
Dim bmp As New Bitmap(dlg.FileName)
currentPhotoCell.Value = bmp
End Sub
为上下文菜单设置CurrentPhotoCell变量值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Sub EmployeesDataGridView_CellContextMenuStripNeeded(ByVal sender As Object, _
ByVal e As DataGridViewCellContextMenuStripNeededEventArgs _
) Handles EmployeesDataGridView.CellContextMenuStripNeeded
Dim dg As DataGridView = CType(sender, DataGridView)
If TypeOf dg.Columns(e.ColumnIndex) Is DataGridViewImageColumn Then
currentPhotoCell = CType(dg.Rows(e.RowIndex).Cells(e.ColumnIndex), DataGridViewImageCell)
End If
End Sub
ByVal e As DataGridViewCellContextMenuStripNeededEventArgs _
) Handles EmployeesDataGridView.CellContextMenuStripNeeded
Dim dg As DataGridView = CType(sender, DataGridView)
If TypeOf dg.Columns(e.ColumnIndex) Is DataGridViewImageColumn Then
currentPhotoCell = CType(dg.Rows(e.RowIndex).Cells(e.ColumnIndex), DataGridViewImageCell)
End If
End Sub
将DataGridViewImageCell对象中的图像保存到文件中
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Imports System.IO
Imports System.Drawing.Imaging
Private Sub SavePhotoToFileToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs _
) Handles SavePhotoToFileToolStripMenuItem.Click
Const oleOffset As Integer = 78
Const oleTypeStart As Integer = 20
Const oleTypeLength As Integer = 12
Dim imageBytes As Byte() = CType(currentPhotoCell.Value, Byte())
If imageBytes Is Nothing Or imageBytes.Length = 0 Then Return
Dim dlg As New SaveFileDialog
dlg.AddExtension = True
dlg.Filter = "GIF|*.gif|BMP|*.bmp|JPEG|*.jpg;*.jpeg|All Files|*.*"
dlg.FilterIndex = 2
dlg.Title = "Enter a file name for this photo"
dlg.FileName = "EmployeePhoto.bmp"
If dlg.ShowDialog <> Windows.Forms.DialogResult.OK Then Return
Dim tempStream As MemoryStream
Dim type As String = System.Text.Encoding.ASCII.GetString(imageBytes, oleTypeStart, oleTypeLength)
If type = "Bitmap Image" Then
tempStream = New MemoryStream(imageBytes, oleOffset, imageBytes.Length - oleOffset)
Else
tempStream = New MemoryStream(imageBytes, 0, imageBytes.Length)
End If
Dim bmp As New Bitmap(tempStream)
bmp.Save(dlg.FileName, ParseImageFormat(dlg.FileName))
End Sub
Function ParseImageFormat(ByVal filename As String) As ImageFormat
Dim ext As String = Path.GetExtension(filename).ToLower
Select Case ext
Case "bmp"
Return ImageFormat.Bmp
Case "jpg", "jpeg"
Return ImageFormat.Jpeg
Case "gif"
Return ImageFormat.Gif
Case Else
Return ImageFormat.Bmp
End Select
Return Nothing
End Function
Imports System.Drawing.Imaging
Private Sub SavePhotoToFileToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs _
) Handles SavePhotoToFileToolStripMenuItem.Click
Const oleOffset As Integer = 78
Const oleTypeStart As Integer = 20
Const oleTypeLength As Integer = 12
Dim imageBytes As Byte() = CType(currentPhotoCell.Value, Byte())
If imageBytes Is Nothing Or imageBytes.Length = 0 Then Return
Dim dlg As New SaveFileDialog
dlg.AddExtension = True
dlg.Filter = "GIF|*.gif|BMP|*.bmp|JPEG|*.jpg;*.jpeg|All Files|*.*"
dlg.FilterIndex = 2
dlg.Title = "Enter a file name for this photo"
dlg.FileName = "EmployeePhoto.bmp"
If dlg.ShowDialog <> Windows.Forms.DialogResult.OK Then Return
Dim tempStream As MemoryStream
Dim type As String = System.Text.Encoding.ASCII.GetString(imageBytes, oleTypeStart, oleTypeLength)
If type = "Bitmap Image" Then
tempStream = New MemoryStream(imageBytes, oleOffset, imageBytes.Length - oleOffset)
Else
tempStream = New MemoryStream(imageBytes, 0, imageBytes.Length)
End If
Dim bmp As New Bitmap(tempStream)
bmp.Save(dlg.FileName, ParseImageFormat(dlg.FileName))
End Sub
Function ParseImageFormat(ByVal filename As String) As ImageFormat
Dim ext As String = Path.GetExtension(filename).ToLower
Select Case ext
Case "bmp"
Return ImageFormat.Bmp
Case "jpg", "jpeg"
Return ImageFormat.Jpeg
Case "gif"
Return ImageFormat.Gif
Case Else
Return ImageFormat.Bmp
End Select
Return Nothing
End Function
7.1.9 实现Virtual模式
类Fruit的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Public Class Fruit
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Dim _name As String
Public Property Calories() As Decimal
Get
Return _calories
End Get
Set(ByVal value As Decimal)
_calories = value
End Set
End Property
Dim _calories As Decimal
Public Property Carbs() As Decimal
Get
Return _carbs
End Get
Set(ByVal value As Decimal)
_carbs = value
End Set
End Property
Dim _carbs As Decimal
Public Sub New(ByVal name As String, ByVal calories As Decimal, ByVal carbs As Decimal)
Me.Name = name
Me.Calories = calories
Me.Carbs = carbs
End Sub
End Class
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Dim _name As String
Public Property Calories() As Decimal
Get
Return _calories
End Get
Set(ByVal value As Decimal)
_calories = value
End Set
End Property
Dim _calories As Decimal
Public Property Carbs() As Decimal
Get
Return _carbs
End Get
Set(ByVal value As Decimal)
_carbs = value
End Set
End Property
Dim _carbs As Decimal
Public Sub New(ByVal name As String, ByVal calories As Decimal, ByVal carbs As Decimal)
Me.Name = name
Me.Calories = calories
Me.Carbs = carbs
End Sub
End Class
实现Virtual模式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Public Class Form1
Private fruitList As New List(Of Fruit)
Private rowInEdit As Integer = -1
Private fruitInEdit As Fruit = Nothing
Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
With fruitList
.Add(New Fruit("Apple", 44, 10.5))
.Add(New Fruit("Banana", 107, 26))
.Add(New Fruit("Orange", 35, 8.5))
End With
DataGridView1.RowCount = fruitList.Count + 1
End Sub
Sub DataGridView1_CellValueNeeded(ByVal sender As Object, ByVal e As DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded
If e.RowIndex = DataGridView1.RowCount - 1 Then
Return
End If
Dim tmpFruit As Fruit = Nothing
If e.RowIndex = rowInEdit Then
tmpFruit = Me.fruitInEdit
Else
tmpFruit = fruitList(e.RowIndex)
End If
Select Case Me.DataGridView1.Columns(e.ColumnIndex).Name
Case "FruitName"
e.Value = tmpFruit.Name
Case "Calories"
e.Value = tmpFruit.Calories
Case "Carbs"
e.Value = tmpFruit.Carbs
End Select
End Sub
End Class
Private fruitList As New List(Of Fruit)
Private rowInEdit As Integer = -1
Private fruitInEdit As Fruit = Nothing
Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
With fruitList
.Add(New Fruit("Apple", 44, 10.5))
.Add(New Fruit("Banana", 107, 26))
.Add(New Fruit("Orange", 35, 8.5))
End With
DataGridView1.RowCount = fruitList.Count + 1
End Sub
Sub DataGridView1_CellValueNeeded(ByVal sender As Object, ByVal e As DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded
If e.RowIndex = DataGridView1.RowCount - 1 Then
Return
End If
Dim tmpFruit As Fruit = Nothing
If e.RowIndex = rowInEdit Then
tmpFruit = Me.fruitInEdit
Else
tmpFruit = fruitList(e.RowIndex)
End If
Select Case Me.DataGridView1.Columns(e.ColumnIndex).Name
Case "FruitName"
e.Value = tmpFruit.Name
Case "Calories"
e.Value = tmpFruit.Calories
Case "Carbs"
e.Value = tmpFruit.Carbs
End Select
End Sub
End Class
向DataGridView对象添加新行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Sub DataGridView1_NewRowNeeded(ByVal sender As Object, ByVal e As DataGridViewRowEventArgs) Handles DataGridView1.NewRowNeeded
fruitInEdit = New Fruit("", 0, 0)
rowInEdit = DataGridView1.Rows.Count - 1
End Sub
Sub DataGridView1_CellValuePushed(ByVal sender As Object, ByVal e As DataGridViewCellValueEventArgs) Handles DataGridView1.CellValuePushed
Dim tmpFruit As Fruit = Nothing
If e.RowIndex < fruitList.Count Then
If fruitInEdit Is Nothing Then
With fruitList(e.RowIndex)
fruitInEdit = New Fruit(.Name, .Calories, .Carbs)
End With
End If
tmpFruit = fruitInEdit
rowInEdit = e.RowIndex
Else
tmpFruit = fruitInEdit
End If
Dim newValue As String = TryCast(e.Value, String)
Select Case DataGridView1.Columns(e.ColumnIndex).Name
Case "FruitName"
tmpFruit.Name = newValue
Case "Calories"
tmpFruit.Calories = Decimal.Parse(newValue)
Case "Carbs"
tmpFruit.Carbs = Decimal.Parse(newValue)
End Select
End Sub
Sub DataGridView1_RowValidated(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles DataGridView1.RowValidated
If e.RowIndex >= fruitList.Count And e.RowIndex <> DataGridView1.Rows.Count - 1 Then
fruitList.Add(fruitInEdit)
fruitInEdit = Nothing
rowInEdit = -1
ElseIf Not fruitInEdit Is Nothing And e.RowIndex < fruitList.Count Then
fruitList(e.RowIndex) = fruitInEdit
fruitInEdit = Nothing
rowInEdit = -1
Else
fruitInEdit = Nothing
rowInEdit = -1
End If
End Sub
fruitInEdit = New Fruit("", 0, 0)
rowInEdit = DataGridView1.Rows.Count - 1
End Sub
Sub DataGridView1_CellValuePushed(ByVal sender As Object, ByVal e As DataGridViewCellValueEventArgs) Handles DataGridView1.CellValuePushed
Dim tmpFruit As Fruit = Nothing
If e.RowIndex < fruitList.Count Then
If fruitInEdit Is Nothing Then
With fruitList(e.RowIndex)
fruitInEdit = New Fruit(.Name, .Calories, .Carbs)
End With
End If
tmpFruit = fruitInEdit
rowInEdit = e.RowIndex
Else
tmpFruit = fruitInEdit
End If
Dim newValue As String = TryCast(e.Value, String)
Select Case DataGridView1.Columns(e.ColumnIndex).Name
Case "FruitName"
tmpFruit.Name = newValue
Case "Calories"
tmpFruit.Calories = Decimal.Parse(newValue)
Case "Carbs"
tmpFruit.Carbs = Decimal.Parse(newValue)
End Select
End Sub
Sub DataGridView1_RowValidated(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles DataGridView1.RowValidated
If e.RowIndex >= fruitList.Count And e.RowIndex <> DataGridView1.Rows.Count - 1 Then
fruitList.Add(fruitInEdit)
fruitInEdit = Nothing
rowInEdit = -1
ElseIf Not fruitInEdit Is Nothing And e.RowIndex < fruitList.Count Then
fruitList(e.RowIndex) = fruitInEdit
fruitInEdit = Nothing
rowInEdit = -1
Else
fruitInEdit = Nothing
rowInEdit = -1
End If
End Sub
添加删除行和取消取行编辑的功能
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Sub DataGridView1_UserDeletingRow(ByVal sender As Object, ByVal e As DataGridViewRowCancelEventArgs) Handles DataGridView1.UserDeletingRow
If e.Row.Index < fruitList.Count Then
fruitList.RemoveAt(e.Row.Index)
End If
If e.Row.Index = Me.rowInEdit Then
rowInEdit = -1
fruitInEdit = Nothing
End If
End Sub
Sub DataGridView1_CancelRowEdit(ByVal sender As Object, ByVal e As QuestionEventArgs) Handles DataGridView1.CancelRowEdit
If rowInEdit = DataGridView1.Rows.Count - 2 And rowInEdit = fruitList.Count Then
fruitInEdit = New Fruit("", 0, 0)
Else
fruitInEdit = Nothing
rowInEdit = -1
End If
End Sub
If e.Row.Index < fruitList.Count Then
fruitList.RemoveAt(e.Row.Index)
End If
If e.Row.Index = Me.rowInEdit Then
rowInEdit = -1
fruitInEdit = Nothing
End If
End Sub
Sub DataGridView1_CancelRowEdit(ByVal sender As Object, ByVal e As QuestionEventArgs) Handles DataGridView1.CancelRowEdit
If rowInEdit = DataGridView1.Rows.Count - 2 And rowInEdit = fruitList.Count Then
fruitInEdit = New Fruit("", 0, 0)
Else
fruitInEdit = Nothing
rowInEdit = -1
End If
End Sub