Changing the Border Style of a TextBox Control Without Raising Events

When changing the border style of a textbox control in .NET Framework 1.0 and 1.1, the original EDIT window is destroyed and a new window is created. This causes some issues, for example, changing the border style fires the control’s Enter event.

Private m_BorderStyle As BorderStyle

Public Property BorderStyle() As BorderStyle
    Get
        Return m_BorderStyle
    End Get
    Set(ByVal Value As BorderStyle)
        m_BorderStyle = Value
        Me.RecreateHandle()
        Me.Invalidate()
    End Set
End Property

Protected Overrides ReadOnly Property CreateParams() As CreateParams
    Get
        Const WS_BORDER As Int32 = &H800000
        Const WS_EX_STATICEDGE As Int32 = &H20000
        Dim cp As CreateParams = MyBase.CreateParams
        Select Case m_BorderStyle
            Case BorderStyle.FixedSingle
                cp.Style = cp.Style Or WS_BORDER
            Case BorderStyle.Fixed3D
                cp.ExStyle = cp.ExStyle Or WS_EX_STATICEDGE
            'Case BorderStyle.None
            '    '
        End Select
        Return cp
    End Get
End Property

Instead of adjusting the window styles with P/Invoke on GetWindowLong, the RecreateHandle method is called which causes the Get procedure of the CreateParams property to be called. There, the style bits are adjusted according to the selected border style. The solution shown above is fully managed, nevertheless it causes wrong behavior, or in other words, “buggy” behavior. The class ExtendedTextBox does not have this problem and does not make use of unmanaged code too:

Imports System
Imports System.ComponentModel
Imports System.Windows.Forms

''' <summary>
'''   An extended textbox control that fixes a bug in the implementation
'''   of the textbox's <c>BorderStyle</c> property.
''' <summary>
Public Class ExtendedTextBox
    Inherits TextBox

    Private Const WS_BORDER As Int32 = &H800000
    Private Const WS_EX_CLIENTEDGE As Int32 = &H200

    Private m_BorderStyle As BorderStyle = BorderStyle.Fixed3D

    Protected Overrides ReadOnly Property CreateParams() As CreateParams
        Get

            ' Adjust window styles to reflect border style selected for
            ' this class.
            Dim cp As CreateParams = MyBase.CreateParams
            Dim dwStyle As Int32 = cp.Style
            Dim dwExStyle As Int32 = cp.ExStyle
            BorderStyleToWindowStyle(Me.BorderStyle, dwStyle, dwExStyle)
            cp.Style = dwStyle
            cp.ExStyle = dwExStyle
            Return cp
        End Get
    End Property

    ''' <summary>
    '''   Gets or sets the border style of the textbox.
    ''' </summary>
    ''' <value>The border style of the textbox.</value>
    ''' <remarks>
    '''   This property behaves slightly differently from the original
    '''   implementation.  If the border is changed on the framework's
    '''   textbox control, the control's size is adjusted.  This is not
    '''   the case for this control.
    ''' </remarks>
    < _
        Category("Appearance"), _
        Description("Gets or sets the border style of the textbox."), _
        DefaultValue(GetType(BorderStyle), "Fixed3D") _
    > _
    Public Shadows Property BorderStyle() As BorderStyle
        Get
            Return m_BorderStyle
        End Get
        Set(ByVal Value As BorderStyle)
            If Value <> Me.BorderStyle Then
                m_BorderStyle = Value

                ' Calls 'CreateParams' and updates the window styles
                ' accordingly.
                Me.UpdateStyles()
            End If
        End Set
    End Property

    Private Sub BorderStyleToWindowStyle( _
        ByVal BorderStyle As BorderStyle, _
        ByRef dwStyle As Int32, _
        ByRef dwExStyle As Int32 _
    )
        dwStyle = dwStyle And Not WS_BORDER
        dwExStyle = dwExStyle And Not WS_EX_CLIENTEDGE
        Select Case BorderStyle
            Case BorderStyle.Fixed3D
                dwExStyle = dwExStyle Or WS_EX_CLIENTEDGE
            Case BorderStyle.FixedSingle
                dwStyle = dwStyle Or WS_BORDER
            'Case BorderStyle.None
            '    '
        End Select
    End Sub
End Class

The code below can be used to check if changing the control’s border style causes a change of the control’s handle. If the handle is different from the handle obtained before changing the border style, the control was recreated:

Dim Handle As IntPtr

' Original textbox.
Dim TextBox1 As New TextBox()
Handle = TextBox1.Handle
TextBox1.BorderStyle = BorderStyle.FixedSingle
MsgBox(Handle.Equals(TextBox1.Handle))

' Textbox with fix applied.
Dim TextBox2 As New ExtendedTextBox()
Handle = TextBox2.Handle
TextBox2.BorderStyle = BorderStyle.FixedSingle
MsgBox(Handle.Equals(TextBox2.Handle))

There is a known issue for the textbox replacement described above. When changing the border stye to FixedSingle at designtime and then rebuilding the solution, the border will be shown incorrectly. This does not occur at runtime.

Borders that can be edited at design time can be added to user controls: Adding designable borders to user controls.