﻿Imports System.ComponentModel

Public Class DataGridViewPasswordTextBoxCell
    Inherits DataGridViewTextBoxCell

    Private editingControlPasswordChar As Char
    Private editingControlUseSystemPasswordChar As Boolean

    Public Property PasswordChar As Char
    Public Property UseSystemPasswordChar As Boolean

    Public Overrides Function Clone() As Object
        Dim copy = DirectCast(MyBase.Clone(), DataGridViewPasswordTextBoxCell)

        copy.PasswordChar = PasswordChar
        copy.UseSystemPasswordChar = UseSystemPasswordChar

        Return copy
    End Function

    Protected Overrides Function GetFormattedValue(value As Object,
                                                   rowIndex As Integer,
                                                   ByRef cellStyle As DataGridViewCellStyle,
                                                   valueTypeConverter As TypeConverter,
                                                   formattedValueTypeConverter As TypeConverter,
                                                   context As DataGridViewDataErrorContexts) As Object
        Dim formattedValue As Object

        If UseSystemPasswordChar AndAlso value IsNot Nothing Then
            'Display the system password character in place of each actual character.
            'TODO: Determine the actual system password character instead of hard-coding this value.
            formattedValue = New String(Convert.ToChar(&H25CF), value.ToString().Length)
        ElseIf PasswordChar <> Char.MinValue AndAlso value IsNot Nothing Then
            'Display the user-defined password character in place of each actual character.
            formattedValue = New String(PasswordChar, value.ToString().Length)
        Else
            'Display the value as is.
            formattedValue = MyBase.GetFormattedValue(value,
                                                      rowIndex,
                                                      cellStyle,
                                                      valueTypeConverter,
                                                      formattedValueTypeConverter,
                                                      context)
        End If

        Return formattedValue
    End Function

    Public Overrides Sub InitializeEditingControl(rowIndex As Integer,
                                                  initialFormattedValue As Object,
                                                  dataGridViewCellStyle As DataGridViewCellStyle)
        'Use the cell's Value rather than the initialFormattedValue because the latter contains the mask characters.
        'We want the editing control to do the masking itself rather than actually contain the mask characters.
        MyBase.InitializeEditingControl(rowIndex, Value, dataGridViewCellStyle)

        With DirectCast(DataGridView.EditingControl, TextBox)
            'Remember the current password properties of the editing control.
            editingControlPasswordChar = .PasswordChar
            editingControlUseSystemPasswordChar = .UseSystemPasswordChar

            'Set the new password properties of the editing control.
            .PasswordChar = PasswordChar
            .UseSystemPasswordChar = UseSystemPasswordChar
        End With
    End Sub

    Public Overrides Sub DetachEditingControl()
        MyBase.DetachEditingControl()

        With DirectCast(DataGridView.EditingControl, TextBox)
            .Clear()

            'Reset the old password properties of the editing control.
            .PasswordChar = editingControlPasswordChar
            .UseSystemPasswordChar = editingControlUseSystemPasswordChar
        End With
    End Sub

End Class