DataGridView控件Bug修复与扩展(.NET FX2.0)
时间:2011-05-24 来源:祭天
因为有注释,这个就直接上码了,有问题就跟贴吧!~
View CodeImports System.Drawing
Imports System.ComponentModel
Public Class DataGridViewEx
Inherits DataGridView
Private m_showLineNumbers As Boolean = False
Private m_trimCommittingText As Boolean = False
Private m_isBinding As Boolean = False
Private m_prevRowIndex As Integer = -1
Public Sub New()
Me.DoubleBuffered = True
End Sub
<Browsable(True), DefaultValue(False)> _
Public Property ShowLineNumbers() As Boolean
Get
Return Me.m_showLineNumbers
End Get
Set(ByVal value As Boolean)
If (Me.m_showLineNumbers <> value) Then
Me.m_showLineNumbers = value
Me.Invalidate()
End If
End Set
End Property
<Browsable(True), DefaultValue(False)> _
Public Property TrimCommittingText() As Boolean
Get
Return Me.m_trimCommittingText
End Get
Set(ByVal value As Boolean)
If (Me.m_trimCommittingText <> value) Then
Me.m_trimCommittingText = value
End If
End Set
End Property
'<Browsable(False), DefaultValue(False)> _
'Public Property IsBinding() As Boolean
' Get
' Return Me.m_isBinding
' End Get
' Set(ByVal value As Boolean)
' Me.m_isBinding = value
' End Set
'End Property
<Browsable(False)> _
Public ReadOnly Property SelectedRow() As DataGridViewRow
Get
If (Me.SelectedRows.Count = 0) Then
Return Nothing
Else
Return Me.SelectedRows(0)
End If
End Get
End Property
<Browsable(False)> _
Public ReadOnly Property SelectedRowIndex() As Integer
Get
If (Me.SelectedRows.Count = 0) Then
Return -1
Else
Return Me.SelectedRows(0).Index
End If
End Get
End Property
Public Shadows Property DataSource() As Object
Get
Return MyBase.DataSource
End Get
Set(ByVal value As Object)
Try
Me.m_isBinding = True
MyBase.DataSource = value
If (Me.m_showLineNumbers) Then
Me.AutosizeRowHeader()
End If
Finally
Me.m_isBinding = False
End Try
End Set
End Property
Protected Overrides Sub OnRowPostPaint(ByVal e As System.Windows.Forms.DataGridViewRowPostPaintEventArgs)
MyBase.OnRowPostPaint(e)
If (Me.RowHeadersVisible AndAlso Me.m_showLineNumbers) Then
If (e.RowIndex <> Me.NewRowIndex) Then
Try
Dim rectangle As New Rectangle(e.RowBounds.Location.X, e.RowBounds.Location.Y, Me.RowHeadersWidth - 4, e.RowBounds.Height)
TextRenderer.DrawText(e.Graphics, (e.RowIndex + 1).ToString(), Me.RowHeadersDefaultCellStyle.Font, rectangle, Me.RowHeadersDefaultCellStyle.ForeColor, TextFormatFlags.VerticalCenter Or TextFormatFlags.Right)
Catch
'do nothing
End Try
End If
End If
End Sub
Public Sub AutosizeRowHeader()
Dim width As Integer = 25 + TextRenderer.MeasureText(Me.RowCount.ToString(), Me.RowHeadersDefaultCellStyle.Font).Width
If (Me.RowHeadersWidth < width) Then
Me.RowHeadersWidth = width
End If
End Sub
Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
'非編輯狀態下,回車鍵選擇下一個單元格
If (Me.SelectionMode <> DataGridViewSelectionMode.FullRowSelect AndAlso Me.EditMode <> DataGridViewEditMode.EditOnEnter) Then
If (e.Modifiers = Keys.None AndAlso e.KeyCode = Keys.Enter) Then
e.Handled = True
Dim currRowIndex As Integer = Me.CurrentCell.RowIndex
Dim currColumnIndex As Integer = Me.CurrentCell.ColumnIndex
If (currColumnIndex < Me.Columns.Count - 1) Then
Dim tmpCell As DataGridViewCell = Me.Rows(currRowIndex).Cells(currColumnIndex + 1)
If (tmpCell.Visible) Then
Me.CurrentCell = tmpCell
End If
ElseIf (currRowIndex < Me.Rows.Count - 1) Then
Dim tmpCell As DataGridViewCell = Me.Rows(currRowIndex + 1).Cells(0)
If (tmpCell.Visible) Then
Me.CurrentCell = tmpCell
End If
End If
End If
End If
MyBase.OnKeyDown(e)
End Sub
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
'編輯狀態下按回車鍵時,替換為 TAB 鍵
If (keyData = Keys.Enter) Then
If (Me.CurrentCell IsNot Nothing AndAlso Me.CurrentCell.IsInEditMode) Then
SendKeys.Send("{TAB}")
Return True
End If
End If
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
Protected Overrides Sub OnSelectionChanged(ByVal e As System.EventArgs)
Dim currRowIndex As Integer = Me.SelectedRowIndex
If (Me.m_prevRowIndex = currRowIndex) Then
Return
End If
Me.m_prevRowIndex = currRowIndex
If (Not MyBase.ContainsFocus OrElse Me.m_isBinding) Then
Return
End If
MyBase.OnSelectionChanged(e)
End Sub
'Protected Overrides Sub OnCellEnter(ByVal e As System.Windows.Forms.DataGridViewCellEventArgs)
' MyBase.OnCellEnter(e)
' Dim col As DataGridViewColumn = Me.Columns(e.ColumnIndex)
' '如果不是只讀,直接進入編輯狀態
' If (Not col.ReadOnly) Then
' Me.BeginEdit(True)
' '如果是下拉列表,直接彈出
' If (TypeOf col Is DataGridViewComboBoxColumn) Then
' DirectCast(Me.EditingControl, DataGridViewComboBoxEditingControl).DroppedDown = True
' End If
' End If
'End Sub
''' <summary>
''' 值提交時,去除前後空格
''' </summary>
Protected Overrides Sub OnCellValidating(ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs)
If (Me.m_trimCommittingText) Then
Dim cell As DataGridViewCell = Me.Rows(e.RowIndex).Cells(e.ColumnIndex)
If (cell.IsInEditMode) Then
If (TypeOf Me.Columns(e.ColumnIndex) Is DataGridViewTextBoxColumn) Then
Dim nowValue As String = Me.EditingControl.Text
If (cell.FormattedValue = nowValue) Then
Return
Else
If (Not String.IsNullOrEmpty(nowValue)) Then
Dim trimValue As String = nowValue.Trim()
If (nowValue.Length <> trimValue.Length) Then
Me.EditingControl.Text = trimValue
Dim ctor As System.Reflection.ConstructorInfo = GetType(DataGridViewCellValidatingEventArgs).GetConstructor( _
Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Public _
, Nothing _
, New Type() {GetType(Integer), GetType(Integer), GetType(Object)} _
, Nothing)
Dim args As DataGridViewCellValidatingEventArgs = ctor.Invoke(New Object() {e.ColumnIndex, e.RowIndex, trimValue})
MyBase.OnCellValidating(args)
Return
End If
End If
End If
End If
End If
End If
MyBase.OnCellValidating(e)
End Sub
Private m_tempAllowUserToAddRows As Boolean = False
Protected Overrides Sub OnUserDeletingRow(ByVal e As System.Windows.Forms.DataGridViewRowCancelEventArgs)
'Bug: 當刪除多行時,如果當前行是空行,刪除操作後,如果不對空行進行添加數據,而是操作別的行,此時再點擊空行,就會引發錯誤。
'Fix: 刪除操作時,如果當前行是空行,將其變更為前一行。(不用判斷索引號,因為單獨對空行是無法刪除的)
If (Me.AllowUserToAddRows) Then
If (Me.CurrentRow IsNot Nothing AndAlso Me.CurrentRow.IsNewRow) Then
Me.CurrentCell = Me.Rows(Me.CurrentCell.RowIndex - 1).Cells(Me.CurrentCell.ColumnIndex)
End If
End If
MyBase.OnUserDeletingRow(e)
'Bug: 如果刪除的行為第一行,而且允許添加行,則不會觸發用戶刪除行事件。
'Fix: 臨時儲存允許添加行標識,在用戶刪除行事件裡還原回來。
If (Not e.Cancel) Then
Me.m_tempAllowUserToAddRows = Me.AllowUserToAddRows
Me.AllowUserToAddRows = False
End If
End Sub
Protected Overrides Sub OnUserDeletedRow(ByVal e As System.Windows.Forms.DataGridViewRowEventArgs)
Me.AllowUserToAddRows = Me.m_tempAllowUserToAddRows
MyBase.OnUserDeletedRow(e)
End Sub
Protected Overrides Sub OnDataError(ByVal displayErrorDialogIfNoHandler As Boolean, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs)
' ComboBox 列產生數據錯誤時,不彈出提示
If (TypeOf Me.Columns(e.ColumnIndex) Is DataGridViewComboBoxColumn) Then
displayErrorDialogIfNoHandler = False
Else
'編輯時,如果轉換失敗,不彈出提示
If (Me.Rows(e.RowIndex).Cells(e.ColumnIndex).IsInEditMode) Then
If (e.Context Or DataGridViewDataErrorContexts.Parsing = e.Context) Then
displayErrorDialogIfNoHandler = False
End If
End If
End If
MyBase.OnDataError(displayErrorDialogIfNoHandler, e)
End Sub
Protected Overrides Sub OnHandleDestroyed(ByVal e As System.EventArgs)
'Bug: 如果當前行是空行,在控件被銷毀之前依舊是空行,則數據源中不會銷毀添加的空行。
'Fix: 被銷毀之前,如果當前行是空行,取消選擇。
If (Me.AllowUserToAddRows) Then
If (Me.CurrentRow IsNot Nothing AndAlso Me.CurrentRow.IsNewRow) Then
Me.CurrentCell = Nothing
End If
End If
MyBase.OnHandleDestroyed(e)
End Sub
End Class
相关阅读 更多 +