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.