How to set TextBox hint label in VB .NET? - vb.net

In my application I have one text box for entering user name. If text is empty i want to show "Enter User name here" in same text box in gray color. Is there any property like this for text box. Like in Firefox browser if URL field is empty it will show "Go to a web site" In gray color
Thanks

I know this may be an old thread, but I thought I'd answer it just in case anyone else stumbled across it.
First declare the following (you may need to import System.Runtime.InteropServices)
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As Int32
End Function
Then call the following (change as needed):
SendMessage(Me.textbox1.Handle, &H1501, 0, "Enter User name here")

Assuming you mean Windows Forms, take a look at this question.
Basically, you need to call a WinAPI SendMessage function for the control with EM_SETCUEBANNERvalue.

I really like this solution from CodeProject.com: http://www.codeproject.com/KB/edit/TextBoxHint.aspx?display=Print
What's really nice is the slick fade out as the user types in his/her text into the field. It's pretty darn easy to implement and looks great.

you can subclass TextBox and override WndProc
Public Class TextBoxPlaceHolder
Inherits TextBox
Private Const WM_PAINT As Int32 = &HF
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
If m.Msg = WM_PAINT AndAlso Me.TextLength = 0 Then
Using g = Me.CreateGraphics
g.DrawString("Enter User name here", Me.Font, Brushes.Gray, 1, 1)
End Using
End If
End Sub
End Class

Awesome work Ivan and cardmagik.
Create a usercontrol and use the below code.
Public Class RichTextBoxPlaceHolder
Inherits RichTextBox
Private Const WM_PAINT As Int32 = &HF
Private mstrHint As String = "Enter text"
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
If m.Msg = WM_PAINT AndAlso Me.TextLength = 0 Then
Using g = Me.CreateGraphics
g.DrawString(mstrHint, Me.Font, Brushes.Gray, 1, 1)
End Using
End If
End Sub
Public Property Hint() As String
Get
Return mstrHint
End Get
Set(ByVal value As String)
mstrHint = value
End Set
End Property
End Class
Screenshot:

Try something along the lines of this:
(onkeyup)
If TextBox.Text = "" Then
TextBox.Text = "Enter username here..."
TextBox.ForeColor = <your chosen color here>
Else
TextBox.ForeColor = <normal color here>
End If

Related

Winforms Panel and Scrollbar issue

This issue has bugged me for some time - when attempting to scroll down a Panel the bar will not move until the mouse is released (doesn't seem to be a problem in other controls).
In this forum http://csharpcode25.appspot.com/question/5080f1624f1eba38a4ca86bf the user has experienced the same problem and a possible solution is given by overriding WndProc - not sure if something got lost in translation from C# to VB but it just throws an error 'Type of argument 'Number' is 'System.IntPtr', which is not numeric.' at the first line. Any ideas?
Thanks
Public Class Panelx
Inherits Panel
Private Const WM_HSCROLL As Integer = &H114
Private Const WM_VSCROLL As Integer = &H115
Protected Overrides Sub WndProc(ByRef m As Message)
Try
If (m.Msg = WM_HSCROLL OrElse m.Msg = WM_VSCROLL) AndAlso ((CInt(Fix(m.WParam)) And &HFFFF) = 5) Then
' Change SB_THUMBTRACK to SB_THUMBPOSITION
m.WParam = CType((CInt(Fix(m.WParam)) And (Not &HFFFF)) Or 4, IntPtr)
End If
MyBase.WndProc(m)
Catch ex As Exception
EmailError(ex)
End Try
End Sub
End Class
Just remove the calls to the Fix() method:
If (m.Msg = WM_HSCROLL OrElse m.Msg = WM_VSCROLL) AndAlso ((CInt(m.WParam) And &HFFFF) = 5) Then
' Change SB_THUMBTRACK to SB_THUMBPOSITION
m.WParam = CType((CInt(m.WParam) And (Not &HFFFF)) Or 4, IntPtr)
End If

How do I implement a TextChanging property on a TextBox?

I figured there would be a question like this already, but I didn't have any luck searching. I saw a question where someone asked the same thing but the answer was to use the TextChanged event. That's not what I want though.
TextBox has an event for TextChanged that occurs after the Text property has been changed. I need my control to raise an event before the Text property is actually changed to validate data. If it is valid the Text can be changed, if it is not valid the Text does not get changed.
Here's what I tried:
Public Class TextChangingEventArgs
Inherits System.ComponentModel.CancelEventArgs
Private p_sNewValue As String
Public Sub New()
p_sNewValue = String.Empty
End Sub
Public Sub New(sNewValue As String)
p_sNewValue = sNewValue
End Sub
Public Property NewValue As String
Get
Return p_sNewValue
End Get
Set(value As String)
p_sNewValue = value
End Set
End Property
End Class
Public Class BetterTextBox
Inherits TextBox
Public Event TextChanging(sender As Object, e As TextChangingEventArgs)
Public Overrides Property Text As String
Get
Return MyBase.Text
End Get
Set(value As String)
Dim e As New TextChangingEventArgs(value)
RaiseEvent TextChanging(Me, e)
If e.Cancel = False Then
MyBase.Text = value
End If
End Set
End Property
End Class
My in my Form I handle the TextChanging event:
Private Sub BetterTextBox1_TextChanging(sender As System.Object, e As TextChangingEventArgs) Handles BetterTextBox1.TextChanging
e.Cancel = Not Regex.IsMatch(e.NewValue, REGEX_PATTERN)
End Sub
This works for programmatically setting the Text value of the BetterTextBox control, but it does not work when you are typing into the text box.
Does anyone know what I need to do to get this to work?
Since you are already inheriting from TextBox, you can override WndProc and check for paste messages. This should resolve the right-click > Paste problem. You could then handle "regular," typed text in KeyPressed or KeyDown, as others have suggested.
Here's an example of what I'm talking about:
Private Const WM_PASTE As Integer = &H302
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_PASTE AndAlso Clipboard.ContainsText() AndAlso ShouldAllowPaste(Clipboard.GetText()) Then
MyBase.WndProc(m)
ElseIf m.Msg <> WM_PASTE Then
MyBase.WndProc(m)
End If
End Sub
Try this:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = 8465 Then
If HIWORD(m.WParam) = 1024 Then
' raise your TextChanging event
End If
End If
MyBase.WndProc(m)
End Sub
Public Function HIWORD(ByVal n As Integer) As UInteger
Return CUInt(n >> 16) And CUInt(&HFFFF)
End Function
I would suggest you should try with keydown event. It occurs before textchanged or even before
keypress.
Try the KeyPress event of the Textbox instead.
EDIT : to disable right-click in the Textbox, you can do something like this.
Put this code inside the Textbox's MouseDown event.
If e.Button = MouseButtons.Right Then
MessageBox.Show("can't paste!")
Exit Sub
End If
however I noticed you could still paste text using the key combination Ctrl + V. You can write this code to stop that in the KeyPress event.
If Keys.ControlKey And Keys.V Then
MessageBox.Show("can't paste!")
Exit Sub
End If

custom textboxes in VB.Net

tldr - Made a subclass of Textbox, text looks screwy when it has focus. What's the proper way to handle it?
For my company's VB.Net application, I've been asked to make our textboxes behave like Google's textboxes, ie they need to have a blue-ish border around them when they have focus and a gray-ish border when they do not. I can already accomplish this by setting a textbox's BorderStyle to 'None', then drawing the appropriate rectangle within a form's Paint event. However, I have to do this for each and every single textbox that I use. And our application has quite a few of them. Needless to say, this is a pain and I'd rather have one piece of code that I can call upon.
So I figured that I have two options; I can either make a user control that contains a single textbox which uses the above method, or I can write my own class that inherits from the TextBox class and makes this behavior standard. I have elected to use the latter approach, and via overriding the OnPaint method I have achieved the desired behavior. But now I'm encountering some new pitfalls.
The main problem that I'm having is that text within the textbox is not rendered correctly when the textbox has focus. The text takes on a different font, appears bold, and highlighting looks wonky. If the textbox loses focus, the text looks correct. I suspect that I need to handle drawing for highlighted text differently, but I'm not sure what I need to do. Do I handle it in the OnPaint method or do I need to catch it somewhere else? Do I need to abandon this approach altogether and just make a user control?
Bonus question: for anyone with experience making custom textboxes, are there any tips or gotchas that I need to know about? This is my first time making a custom control, so I don't really know what all to expect.
edit: forgot to mention that I'm able to override OnPaint because I set the UserPaint flag to true. I'm guessing this was obvious, but I just want to be thorough.
edit2: Here's the class in its entirety.
Imports System.Drawing
Public Class MyCustomTextBox
Inherits TextBox
Public Sub New()
MyBase.New()
Me.BorderStyle = BorderStyle.None
SetStyle(ControlStyles.UserPaint, True)
End Sub
Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
'I want these textboxes to highlight all text by default
Me.SelectAll()
MyBase.OnGotFocus(e)
End Sub
Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
Me.SelectionLength = 0
MyBase.OnLostFocus(e)
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
Dim p As Pen = Nothing
'MyBase.OnPaint(e)
e.Graphics.FillRectangle(Brushes.White, Me.ClientRectangle)
If Me.Focused Then
p = New Pen(Brushes.CornflowerBlue)
Else
p = New Pen(Brushes.Gainsboro)
End If
e.Graphics.DrawRectangle(p, 0, 0, Me.ClientSize.Width - 1, Me.ClientSize.Height - 1)
e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), Me.ClientRectangle)
End Sub
End Class
As Hans mentioned, the TextBox doesn't even use the OnPaint method when it draws its text.
One way to do it is paint over the 3D border of the control in the WM_NCPAINT message. I won't claim it's completely flicker free:
Imports System.Runtime.InteropServices
Public Class TextBoxWithBorder
Inherits TextBox
Public Const WM_NCPAINT As Integer = &H85
<Flags()> _
Private Enum RedrawWindowFlags As UInteger
Invalidate = &H1
InternalPaint = &H2
[Erase] = &H4
Validate = &H8
NoInternalPaint = &H10
NoErase = &H20
NoChildren = &H40
AllChildren = &H80
UpdateNow = &H100
EraseNow = &H200
Frame = &H400
NoFrame = &H800
End Enum
<DllImport("User32.dll")> _
Public Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr
End Function
<DllImport("user32.dll")> _
Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean
End Function
<DllImport("user32.dll")> _
Private Shared Function RedrawWindow(hWnd As IntPtr, lprcUpdate As IntPtr, hrgnUpdate As IntPtr, flags As RedrawWindowFlags) As Boolean
End Function
Public Sub New()
MyBase.BorderStyle = Windows.Forms.BorderStyle.Fixed3D
End Sub
Protected Overrides Sub OnResize(e As System.EventArgs)
MyBase.OnResize(e)
RedrawWindow(Me.Handle, IntPtr.Zero, IntPtr.Zero, RedrawWindowFlags.Frame Or RedrawWindowFlags.UpdateNow Or RedrawWindowFlags.Invalidate)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If m.Msg = WM_NCPAINT Then
Dim hDC As IntPtr = GetWindowDC(m.HWnd)
Using g As Graphics = Graphics.FromHdc(hDC)
If Me.Focused Then
g.DrawRectangle(Pens.CornflowerBlue, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
Else
g.DrawRectangle(Pens.Gainsboro, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
End If
g.DrawRectangle(SystemPens.Window, New Rectangle(1, 1, Me.Width - 3, Me.Height - 3))
End Using
ReleaseDC(m.HWnd, hDC)
End If
End Sub
End Class
I override the OnResize event to send the RedrawWindow message, which basically makes the control invalidate it's nonclient area.
Refactor as needed.

How can I extend a DataGridView ComboBox column's edit control by a second tiny button?

I insert DataGridViewComboBoxColumn columns in a DataViewGrid. That works fine.
Now, I want the user to be able to not only select one list item, but to "drilldown" into the list that is behind the combobox, allowing him to edit (insert/delete/update) the list.
I think it would be a good idea to display a ".." button right behind the dropdown button of the combobox. Pushing it leads to a dialog where the list can be maintained.
What I am stumbling upon is:
How would I create such a custom combobox? Is ComboBox (which is the base for the combo box that the combo box column creates as its edit control) open enough to accommodate such an additional button? What would be the container of the tiny buttoon -- the ComboBox descendant?
How I would make the grid create and handle such a custom combobox?
I currently try to solve this by subclassing DataGridViewComboBoxColum, using a DataGridViewComboBoxCell descendent in its CellTemplate assignment, and overriding PositionWEditingPanel and PositionEditingControl to manipulate the sizes of the panel and the combobox so I'd have space for the tiny button.
Is that the correct way?
Or would I have to create a DataGridViewColumn descendant which creates a Panel containing a DataGridView combobox edit control and the tiny button? How would I make sure the column keeps care of the combo box so it has the correct items etc?
Maybe I sound confused, but I probably am after weeks of VB code (doh)....
Here's the code I came up with. Only thing that's missing is the button press event handler.
Improvements welcome!
#Region "Custom column, cell and edit control for Combobox-with-a-'..'-Button"
Public Class DataGridViewComboBoxExColumn
Inherits DataGridViewComboBoxColumn
Public Sub New()
MyBase.New()
CellTemplate = New DataGridViewComboBoxExCell()
End Sub
Public Overrides Property CellTemplate As DataGridViewCell
Get
Return MyBase.CellTemplate
End Get
Set(ByVal value As DataGridViewCell)
If (value IsNot Nothing) AndAlso Not value.GetType().IsAssignableFrom(GetType(DataGridViewComboBoxExCell)) Then
Throw New InvalidCastException("Must be a DataGridViewComboBoxExCell")
End If
MyBase.CellTemplate = value
End Set
End Property
End Class
Public Class DataGridViewComboBoxExCell
Inherits DataGridViewComboBoxCell
Dim HostingPanel As Panel
Public Sub New()
MyBase.New()
Dim TheButton As Button
HostingPanel = New Panel
HostingPanel.BorderStyle = BorderStyle.Fixed3D
HostingPanel.Padding = New Padding(0, 0, 0, 0)
HostingPanel.BackColor = Color.FromKnownColor(KnownColor.Control)
'HostingPanel.ForeColor = Color.Red ' Color.FromKnownColor(KnownColor.ButtonFace)
TheButton = New Button
TheButton.Text = ""
TheButton.BackColor = Color.FromKnownColor(KnownColor.ButtonFace)
TheButton.ImageList = DaCorFredProtMainForm.MainImageList
TheButton.ImageKey = "table_edit.png"
TheButton.Dock = DockStyle.Fill
HostingPanel.Controls.Add(TheButton)
End Sub
Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, ByVal initialFormattedValue As Object, ByVal dataGridViewCellStyle As DataGridViewCellStyle)
MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)
If Not Me.DataGridView.EditingPanel.Controls.Contains(HostingPanel) Then ' Should always be true
Me.DataGridView.EditingPanel.Controls.Add(HostingPanel)
End If
End Sub
Public Overrides Sub DetachEditingControl()
If Me.DataGridView.EditingPanel.Controls.Contains(HostingPanel) Then ' Should always be true
Me.DataGridView.EditingPanel.Controls.Remove(HostingPanel)
End If
MyBase.DetachEditingControl()
End Sub
Public Overrides ReadOnly Property EditType As Type
Get
Return MyBase.EditType
End Get
End Property
Public Overrides ReadOnly Property ValueType As Type
Get
Return MyBase.ValueType
End Get
End Property
Public Overrides Function PositionEditingPanel(ByVal cellBounds As System.Drawing.Rectangle, ByVal cellClip As System.Drawing.Rectangle, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal singleVerticalBorderAdded As Boolean, ByVal singleHorizontalBorderAdded As Boolean, ByVal isFirstDisplayedColumn As Boolean, ByVal isFirstDisplayedRow As Boolean) As System.Drawing.Rectangle
cellBounds.Width += cellBounds.Height
cellClip.Width += cellClip.Height
Return MyBase.PositionEditingPanel(cellBounds, cellClip, cellStyle, singleVerticalBorderAdded, singleHorizontalBorderAdded, isFirstDisplayedColumn, isFirstDisplayedRow)
End Function
Public Overrides Sub PositionEditingControl(ByVal setLocation As Boolean, ByVal setSize As Boolean, ByVal cellBounds As System.Drawing.Rectangle, ByVal cellClip As System.Drawing.Rectangle, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal singleVerticalBorderAdded As Boolean, ByVal singleHorizontalBorderAdded As Boolean, ByVal isFirstDisplayedColumn As Boolean, ByVal isFirstDisplayedRow As Boolean)
MyBase.PositionEditingControl(setLocation, setSize, cellBounds, cellClip, cellStyle, singleVerticalBorderAdded, singleHorizontalBorderAdded, isFirstDisplayedColumn, isFirstDisplayedRow)
Me.DataGridView.EditingControl.Width -= Me.DataGridView.EditingPanel.Height
HostingPanel.Width = Me.DataGridView.EditingPanel.Height
HostingPanel.Height = Me.DataGridView.EditingPanel.Height
HostingPanel.Location = New Point(DataGridView.EditingPanel.Size.Width - DataGridView.EditingPanel.Size.Height, 0)
End Sub
End Class
#End Region

How can I catch the autosize double-click event on a listview in VB.NET?

I am using Visual Studio 2008 and VB.NET. I've got a listview control on my form and I've added columns using the windows forms designer. As you know, if you double-click on the sizer or divider or whatever you want to call it between two columns, the column on the left will autosize (unless you disable that). How can I catch this specific event? The ColumnWidthChanged event and the DoubleClick event are likely candidates, but in the ColumnWidthChanged event, there's no way I can see to determine if it was an autosize. Similarly, there's no simple way to catch what was clicked exactly with the DoubleClick event. Does anyone have any ideas how I can catch this specific event type?
Detecting events on a listview's header is quite tricky.
You will need to create your own header to replace the one that it normally uses, and then listen to the appropriate messages. There aren't any specific ones for column resize handles, as far as I know.
The following class subclasses ListView and adds a handler that detects a double-click between columns. That is as close as it gets, I think.
I hope it will help you out somewhat.
Class MyListView
Inherits ListView
Protected Overrides Sub CreateHandle()
MyBase.CreateHandle()
New HeaderControl(Me)
End Sub
Private Class HeaderControl
Inherits NativeWindow
Private _parent As ListView = Nothing
<DllImport("User32.dll", CharSet := CharSet.Auto, SetLastError := True)> _
Public Shared Function SendMessage(hWnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
End Function
Public Sub New(parent As ListView)
_parent = parent
Dim header As IntPtr = SendMessage(parent.Handle, (&H1000 + 31), IntPtr.Zero, IntPtr.Zero)
Me.AssignHandle(header)
End Sub
Protected Overrides Sub WndProc(ByRef message As Message)
Const WM_LBUTTONDBLCLK As Integer = &H203
Select Case message.Msg
Case WM_LBUTTONDBLCLK
Dim position As Point = Control.MousePosition
Dim relative As Point = _parent.PointToClient(position)
Dim rightBorder As Integer = 0
For Each c As ColumnHeader In _parent.Columns
rightBorder += c.Width
If relative.X > (rightBorder - 6) AndAlso relative.X < (rightBorder + 6) Then
MessageBox.Show([String].Format("Double-click after column '{0}'", c.Text))
End If
Next
Exit Select
End Select
MyBase.WndProc(message)
End Sub
End Class
End Class
You will need to include a using System.Runtime.InteropServices; statement for this to work.