1. Herfried K. Wagner’s VB.Any
  2. .NET
  3. Frequently Asked Questions

Changing the border style of a textbox control without raising events

Changing the border style of a textbox control without raising events
<URL:https://dotnet.currifex.org/dotnet/faqs/textboxborderstyle/en/>
----------------------------------------------------------------------------

Changing the border style of a textbox control without raising events

When changing the border style of a textbox control in .NET 1.0 and
.NET 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.

The sample "Adding a standard border to a control"
(<URL:http://www.bobpowell.net/addborder.htm>) written by Bob Powell [MVP]
suffers from the same problem.  The following listing shows a reworked
version of the listing given in the referenced article:

\\\
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.

An article about designable borders for Windows Forms controls can be found
here:

Adding designable borders to user controls
<URL:http://www.thecodeproject.com/cs/miscctrl/CsAddingBorders.asp>