DataGridViewMaskedTextBoxColumn[VB.NET]

296 阅读4分钟
Imports System
Imports System.Windows.Forms

''' <summary>
''' DataGridViewMaskedTextBoxCellオブジェクトの列を表します。
''' 用于DataGridView中MaskedTextBoxCell的列。
''' </summary>
Public Class DataGridViewMaskedTextBoxColumn
    Inherits DataGridViewColumn

    'CellTemplateとするDataGridViewMaskedTextBoxCellオブジェクトを指定して
    '使用DataGridViewMaskedTextBoxCell对象调用基类构造函数
    Public Sub New()
        MyBase.New(New DataGridViewMaskedTextBoxCell())
    End Sub

    Private maskValue As String = ""
    Private promptValue As String = ""
    Private maskFormatValue As System.Windows.Forms.MaskFormat
    ''' <summary>
    ''' 要应用于MaskedTextBox的Mask属性的值,即格式
    ''' </summary>
    Public Property Mask() As String
        Get
            Return Me.maskValue
        End Get
        Set(ByVal value As String)
            Me.maskValue = value
        End Set
    End Property
    ''' <summary>
    ''' 要应用于MaskedTextBox的PromptChar属性的值
    ''' </summary>
    ''' <returns></returns>
    Public Property Prompt() As String
        Get
            Return Me.promptValue
        End Get
        Set(ByVal value As String)
            Me.promptValue = value
        End Set
    End Property
    ''' <summary>
    ''' 要应用于MaskedTextBox的MaskFormat
    ''' </summary>
    ''' <returns></returns>
    Public Property MaskFormat() As String
        Get
            Return Me.maskFormatValue
        End Get
        Set(ByVal value As String)
            Me.maskFormatValue = value
        End Set
    End Property

    '由于我们添加了新属性,因此我们需要重写克隆方法。
    Public Overrides Function Clone() As Object
        Dim col As DataGridViewMaskedTextBoxColumn =
            DirectCast(MyBase.Clone(), DataGridViewMaskedTextBoxColumn)
        col.Mask = Me.Mask
        col.Prompt = Me.Prompt
        col.MaskFormat = Me.MaskFormat
        Return col
    End Function


    '获取和设置CellTemplate
    Public Overrides Property CellTemplate() As DataGridViewCell
        Get
            Return MyBase.CellTemplate
        End Get
        Set(ByVal value As DataGridViewCell)
            'DataGridViewMaskedTextBoxCellしかCellTemplateに設定できないようにする
            'DataGridViewMaskedTextBoxCell只能设定为CellTemplate
            If Not (TypeOf value Is DataGridViewMaskedTextBoxCell) Then
                Throw New InvalidCastException("指定DataGridViewMaskedTextBoxCell对象。")
            End If
            MyBase.CellTemplate = value
        End Set
    End Property
End Class

''' <summary>
''' 在DataGridView控件中显示可在MaskedTextBox中编辑的文本信息。
''' </summary>
Public Class DataGridViewMaskedTextBoxCell
    Inherits DataGridViewTextBoxCell

    '构造函数
    Public Sub New()
    End Sub

    '初始化编辑控件
    '编辑控件也用于其他单元格和列,因此需要初始化

    Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer,
        ByVal initialFormattedValue As Object,
        ByVal dataGridViewCellStyle As DataGridViewCellStyle)

        MyBase.InitializeEditingControl(rowIndex, initialFormattedValue,
                                        dataGridViewCellStyle)

        '获取编辑控件
        Dim maskedBox As DataGridViewMaskedTextBoxEditingControl =
            TryCast(Me.DataGridView.EditingControl,
                DataGridViewMaskedTextBoxEditingControl)
        If maskedBox IsNot Nothing Then
            '设置Text
            Dim maskedText As String = TryCast(initialFormattedValue, String)
            maskedBox.Text = If(maskedText IsNot Nothing, maskedText, "   :  :  ")
            '反映自定义列的属性
            Dim column As DataGridViewMaskedTextBoxColumn =
                TryCast(Me.OwningColumn, DataGridViewMaskedTextBoxColumn)
            If column IsNot Nothing Then
                maskedBox.Mask = column.Mask
                maskedBox.PromptChar = column.Prompt
                maskedBox.TextMaskFormat=column.MaskFormat
            End If
        End If
    End Sub

    '指定编辑控件的类型
    Public Overrides ReadOnly Property EditType() As Type
        Get
            Return GetType(DataGridViewMaskedTextBoxEditingControl)
        End Get
    End Property

    '指定单元格值的数据类型
    '在此,设为Object与基类相同,无需重写
    Public Overrides ReadOnly Property ValueType() As Type
        Get
            Return GetType(Object)
        End Get
    End Property

    '为新记录行中的单元格指定默认值
    Public Overrides ReadOnly Property DefaultNewRowValue() As Object
        Get
            Return MyBase.DefaultNewRowValue
        End Get
    End Property
End Class

''' <summary>
''' 表示由DataGridViewMaskedTextBoxCell托管的MaskedTextBox。
''' </summary>
Public Class DataGridViewMaskedTextBoxEditingControl
    Inherits MaskedTextBox
    Implements IDataGridViewEditingControl

    '显示编辑控件的DataGridView
    Private dataGridView As DataGridView
    '显示编辑控件的行
    Private rowIndex As Integer
    '编辑控件的值是否与单元格的值不同
    Private valueChanged As Boolean

    '构造函数
    Public Sub New()
        Me.TabStop = False
    End Sub

#Region "IDataGridViewEditingControl メンバ"

    '编辑控件中已更改的单元格的值
    Public Function GetEditingControlFormattedValue(
        ByVal context As DataGridViewDataErrorContexts) As Object _
        Implements IDataGridViewEditingControl.GetEditingControlFormattedValue

        Return Me.Text
    End Function

    '编辑控件中已更改的单元格的值
    Public Property EditingControlFormattedValue() As Object _
        Implements IDataGridViewEditingControl.EditingControlFormattedValue

        Get
            Return Me.GetEditingControlFormattedValue(
                DataGridViewDataErrorContexts.Formatting)
        End Get
        Set(ByVal value As Object)
            Me.Text = DirectCast(value, String)
        End Set
    End Property

    '将单元格样式应用于编辑控件 (前景颜色、背景颜色、字体对齐)
    Public Sub ApplyCellStyleToEditingControl(
        ByVal dataGridViewCellStyle As DataGridViewCellStyle) _
        Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl

        Me.Font = dataGridViewCellStyle.Font
        Me.ForeColor = dataGridViewCellStyle.ForeColor
        Me.BackColor = dataGridViewCellStyle.BackColor
        Select Case dataGridViewCellStyle.Alignment
            Case DataGridViewContentAlignment.BottomCenter,
                DataGridViewContentAlignment.MiddleCenter,
                DataGridViewContentAlignment.TopCenter

                Me.TextAlign = HorizontalAlignment.Center
                Exit Select
            Case DataGridViewContentAlignment.BottomRight,
                DataGridViewContentAlignment.MiddleRight,
                DataGridViewContentAlignment.TopRight

                Me.TextAlign = HorizontalAlignment.Right
                Exit Select
            Case Else
                Me.TextAlign = HorizontalAlignment.Left
                Exit Select
        End Select
    End Sub

    '包含要编辑的单元格的DataGridView
    Public Property EditingControlDataGridView() As DataGridView _
        Implements IDataGridViewEditingControl.EditingControlDataGridView

        Get
            Return Me.dataGridView
        End Get
        Set(ByVal value As DataGridView)
            Me.dataGridView = value
        End Set
    End Property

    '正在编辑的行的索引
    Public Property EditingControlRowIndex() As Integer _
        Implements IDataGridViewEditingControl.EditingControlRowIndex

        Get
            Return Me.rowIndex
        End Get
        Set(ByVal value As Integer)
            Me.rowIndex = value
        End Set
    End Property

    '值是否已更改
    '编辑控件的值和单元格的值是否不同
    Public Property EditingControlValueChanged() As Boolean _
        Implements IDataGridViewEditingControl.EditingControlValueChanged

        Get
            Return Me.valueChanged
        End Get
        Set(ByVal value As Boolean)
            Me.valueChanged = value
        End Set
    End Property

    '指定されたキーをDataGridViewが処理するか、編集コントロールが処理するか
    Public Function EditingControlWantsInputKey(ByVal keyData As Keys,
        ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
        Implements IDataGridViewEditingControl.EditingControlWantsInputKey

        'Keys.Left、Right、Home、End时返回 True;如果不这样做, 这些键会将焦点转移到另一个单元格
        Select Case keyData And Keys.KeyCode
            Case Keys.Right, Keys.[End], Keys.Left, Keys.Home
                Return True
            Case Else
                Return Not dataGridViewWantsInputKey
        End Select
    End Function

    '指定鼠标光标位于“EditingPanel”上时的光标
    '“EditingPanel”是承载编辑控件的面板。
    '如果编辑控件小于单元格,则控件以外的部分将成为panel
    Public ReadOnly Property EditingPanelCursor() As Cursor _
        Implements IDataGridViewEditingControl.EditingPanelCursor

        Get
            Return MyBase.Cursor
        End Get
    End Property

    '准备在控件中编辑
    '选择文本或结束插入符号
    Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
        Implements IDataGridViewEditingControl.PrepareEditingControlForEdit

        If selectAll Then
            '进入选择状态
            Me.SelectAll()
        Else
            '在字节结尾插入符号
            Me.SelectionStart = Me.TextLength
        End If
    End Sub

    '如果值更改,则是否更改单元格位置;如果值更改,需要更改编辑控件大小,则为 True。
    Public ReadOnly Property RepositionEditingControlOnValueChange() As Boolean _
        Implements IDataGridViewEditingControl.RepositionEditingControlOnValueChange

        Get
            Return False
        End Get
    End Property

#End Region

    '当值更改时
    Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)
        MyBase.OnTextChanged(e)
        '通知DataGridView值已更改
        Me.valueChanged = True
        Me.dataGridView.NotifyCurrentCellDirty(True)
    End Sub
    
    '当在输入框按了键时,判断是否是数字,然后更改值
    Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
        MyBase.OnKeyDown(e)
        '在掩码块判断
        If e.KeyCode = Keys.Tab Then
            'Dim pos As Integer = Me.SelectionStart
            'Dim max As Integer = (Me.MaskedTextProvider.Length - Me.MaskedTextProvider.EditPositionCount)
            'Dim nextField As Integer = 0

            'For i As Integer = 0 To Me.MaskedTextProvider.Length - 1
            '    If Not Me.MaskedTextProvider.IsEditPosition(i) AndAlso (pos + max) >= i Then nextField = i
            'Next

            'nextField += 1
            ''完成,开启TabStop
            'If pos = nextField Then Key_Leave(Me, e)
            'Me.SelectionStart = nextField
        ElseIf e.KeyCode = Keys.Enter Then

        ElseIf (e.KeyCode >= Keys.D0 And e.KeyCode <= Keys.D9) Or
            (e.KeyCode >= Keys.NumPad0 And e.KeyCode <= Keys.NumPad9) Then
            Dim pos As Integer = Me.SelectionStart
            '从指定位置开始向前第一个未赋值可编辑的位置,填满了返回-1
            Dim PosNextUnassignedMask = Me.MaskedTextProvider.FindUnassignedEditPositionFrom(pos, True)
            '从指定位置开始向前第一个不可编辑的位置
            Dim PosNextNonEdit = Me.MaskedTextProvider.FindNonEditPositionFrom(pos, True)
            '得到输入的值并判断输入的值是0-9的哪个,并转换成Char
            Dim str = If(((e.KeyValue - Keys.NumPad0) < 0) And (e.KeyValue >= Keys.D0 And e.KeyValue <= Keys.NumPad9),
                CChar((e.KeyValue - Keys.D0).ToString),
                DirectCast(CChar((e.KeyValue - Keys.NumPad0).ToString), Object))

            '已经填满了字符串的话,输入变成插入(把光标后一个字符替换了,只能替换最近掩码前的)
            If PosNextUnassignedMask < 0 Then
                '光标在掩码前,则更改下一个掩码区第一个可编辑的位置
                If (PosNextNonEdit = pos) Then
                    Dim tmp = Me.Text.ToCharArray
                    tmp(pos + 1) = str
                    Dim tmp2 As String = ""
                    For i = 0 To tmp.Length - 1
                        tmp2 = tmp2 & tmp(i)
                    Next
                    Me.Text = tmp2
                    Me.SelectionStart = pos + 2
                    '这个改不了值
                    'Me.MaskedTextProvider.Replace(str, PosNextNonEdit + 1)
                    'Me.MaskedTextProvider.InsertAt(str, PosNextNonEdit + 1)
                Else
                    Dim tmp = Me.Text.ToCharArray
                    tmp(pos) = str
                    Dim tmp2 As String = ""
                    For i = 0 To tmp.Length - 1
                        tmp2 = tmp2 & tmp(i)
                    Next
                    Me.Text = tmp2
                    Me.SelectionStart = pos + 1

                End If
            End If
        End If
    End Sub
End Class