Search code examples
.netvb.netwinformstextbox

how to change the position of the icon in the textbox class with VB.NET


I'm trying to change the position of the icon in the textbox class with VB.NET

Public Class SearchTextBox
        Inherits TextBox
        Private Const EM_SETMARGINS As Integer = &Hd3
        <System.Runtime.InteropServices.DllImport("user32.dll")>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr
        End Function

        Private searchPictureBox As PictureBox

        Private cancelSearchButton As Button

        Public Sub New()
            cancelSearchButton = New Button()
            cancelSearchButton.Anchor = AnchorStyles.Top Or AnchorStyles.Right
            cancelSearchButton.Size = New Size(16, 16)
            cancelSearchButton.TabIndex = 0
            cancelSearchButton.TabStop = False
            cancelSearchButton.FlatStyle = FlatStyle.Flat
            cancelSearchButton.FlatAppearance.BorderSize = 0
            cancelSearchButton.Text = ""
            cancelSearchButton.Cursor = Cursors.Arrow

            Controls.Add(cancelSearchButton)

            AddHandler cancelSearchButton.Click, Sub()
                Text = ""
                Focus()
            End Sub

            searchPictureBox = New PictureBox()
            searchPictureBox.Anchor = AnchorStyles.Top Or AnchorStyles.Right
            searchPictureBox.Size = New Size(16, 16)
            searchPictureBox.TabIndex = 0
            searchPictureBox.TabStop = False
            Controls.Add(searchPictureBox)

            ' Send EM_SETMARGINS to prevent text from disappearing underneath the button
            SendMessage(Handle, EM_SETMARGINS, New IntPtr(2), New IntPtr(16 << 16))

            UpdateControlsVisibility()
        End Sub

        Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)
            MyBase.OnTextChanged(e)
            UpdateControlsVisibility()
        End Sub

        Private Sub UpdateControlsVisibility()
            If String.IsNullOrEmpty(Text) Then
                cancelSearchButton.Visible = False
                searchPictureBox.Visible = True
            Else
                cancelSearchButton.Visible = True
                searchPictureBox.Visible = False
            End If
        End Sub

        <Browsable(True)>
        Public Property SearchImage As Image
            Set(ByVal value As Image)
                searchPictureBox.Image = value
                searchPictureBox.Left = Width - searchPictureBox.Size.Width - 4
                searchPictureBox.Top = Height - searchPictureBox.Size.Height - 4
            End Set

            Get
                Return searchPictureBox.Image
            End Get
        End Property

        <Browsable(True)>
        Public Property CancelSearchImage As Image
            Set(ByVal value As Image)
                cancelSearchButton.Image = value
                cancelSearchButton.Left = Width - searchPictureBox.Size.Width - 4
                cancelSearchButton.Top = Height - searchPictureBox.Size.Height - 4
            End Set

            Get
                Return cancelSearchButton.Image
            End Get
        End Property
    End Class

result from code

result from code

Desired Result

Desired Output


Solution

  • Here is your code with the expected result.

    Edit : I added an overide for OnSizeChanged in order to correctly position the icons when the size of the textbox changes

    Imports System.ComponentModel
    
    Public Class SearchTextBox
        Inherits TextBox
    
        Private Const EM_SETMARGINS As Integer = &HD3
    
        <System.Runtime.InteropServices.DllImport("user32.dll")>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wp As IntPtr, ByVal lp As IntPtr) As IntPtr
        End Function
    
        Private ReadOnly _IconPictureBox As PictureBox
    
        Private _searchImage As Image
    
        Private _cancelSearchImage As Image
    
    
        Public Sub New()
            _IconPictureBox = New PictureBox With {
                .Anchor = AnchorStyles.Top Or AnchorStyles.Right,
                .Size = New Size(Height - (Margin.Vertical + 2), Height - (Margin.Vertical + 2)),
                .Top = Margin.Top,
                .Left = Margin.Left,
                .TabIndex = 0,
                .TabStop = False,
                .SizeMode = PictureBoxSizeMode.StretchImage
            }
            AddHandler _IconPictureBox.Click, Sub()
                                                  Text = ""
                                                  Focus()
                                              End Sub
            Controls.Add(_IconPictureBox)
    
            ' Send EM_SETMARGINS to prevent text from disappearing underneath the button
            SendMessage(Handle, EM_SETMARGINS, New IntPtr(2), New IntPtr(16 << 16))
        End Sub
    
        Protected Overrides Sub OnTextChanged(ByVal e As EventArgs)
            MyBase.OnTextChanged(e)
            UpdateIcon()
        End Sub
    
        Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs)
            MyBase.OnSizeChanged(e)
            UpdateIcon()
        End Sub
    
        Private Sub UpdateIcon()
            If String.IsNullOrEmpty(Text) Then
                _IconPictureBox.Image = _searchImage
                _IconPictureBox.Left = Margin.Left
            Else
                _IconPictureBox.Image = _cancelSearchImage
                _IconPictureBox.Cursor = Cursors.Arrow
                _IconPictureBox.Left = Width - _IconPictureBox.Size.Width - Margin.Horizontal
            End If
        End Sub
    
        <Browsable(True)>
        Public Property SearchImage As Image
            Set(value As Image)
                _searchImage = value
                UpdateIcon()
            End Set
    
            Get
                Return _searchImage
            End Get
        End Property
    
        <Browsable(True)>
        Public Property CancelSearchImage As Image
            Set(value As Image)
                _cancelSearchImage = value
                UpdateIcon()
            End Set
    
            Get
                Return _cancelSearchImage
            End Get
        End Property
    End Class
    

    Here is the result :

    • When the textbox is empty :

    When textbox is empty

    • When there is content :

    When
there is content

    If necessary, here are the images I used :