SOLUTION:
Thanks to Patrick below, I have refactored the C# CodeProject version into a VB.NET version that works for me. Hopefully it can help you guys as well:
Partial Public Class WatermarkedTextBox Inherits TextBox Private _waterMarkColor As Color = Color.LightGray Public Property WaterMarkColor() As Color Get Return _waterMarkColor End Get Set(ByVal value As Color) _waterMarkColor = value End Set End Property Private _waterMarkText As String = "Watermark" Public Property WaterMarkText() As String Get Return _waterMarkText End Get Set(ByVal value As String) _waterMarkText = value End Set End Property Sub New() End Sub Protected Overloads Overrides Sub OnCreateControl() MyBase.OnCreateControl() End Sub Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) MyBase.WndProc(m) Const WM_PAINT As Integer = &HF If m.Msg = WM_PAINT Then If Text.Length <> 0 Then Return End If Using g As Graphics = Me.CreateGraphics g.DrawString(WaterMarkText, Me.Font, New SolidBrush(WaterMarkColor), 0, 0) End Using End If End Sub Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs) MyBase.OnTextChanged(e) Invalidate() End Sub Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs) MyBase.OnLostFocus(e) Invalidate() End Sub Protected Overrides Sub OnFontChanged(ByVal e As System.EventArgs) MyBase.OnFontChanged(e) Invalidate() End Sub Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs) '' added so the watermark is not cleared until text is entered MyBase.OnGotFocus(e) Invalidate() End Sub End Class
I am building a kiosk application, and in order to keep it aesthetically pleasing I decided to implement a watermarked textbox as the entry fields. I found this project on CodeProject, converted it over to VB.NET and put it into my application. It works, in the sense that it watermarks and clears them just fine, but when I go to enter text this happens:
Empty:

Filled:

So basically it is not clearing the whole watermark, just the space appropriated for the default height of a textbox. here is the converted code:
Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Windows.Forms Imports System.Drawing Partial Public Class WatermarkedTextBox Inherits TextBox Private oldFont As Font = Nothing Private waterMarkTextEnabled As Boolean = False #Region "Attributes" Private _waterMarkColor As Color = Color.LightGray Public Property WaterMarkColor() As Color Get Return _waterMarkColor End Get Set(ByVal value As Color) _waterMarkColor = value Invalidate() End Set End Property Private _waterMarkText As String = "Water Mark" Public Property WaterMarkText() As String Get Return _waterMarkText End Get Set(ByVal value As String) _waterMarkText = value Invalidate() End Set End Property #End Region Public Sub New() JoinEvents(True) End Sub Protected Overloads Overrides Sub OnCreateControl() MyBase.OnCreateControl() WaterMark_Toggle(Nothing, Nothing) End Sub Protected Overloads Overrides Sub OnPaint(ByVal args As PaintEventArgs) 'Dim drawFont As New System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit) Dim drawFont As New Font("Arial", 28, FontStyle.Bold) 'New System.Drawing.Font(oldFont.FontFamily, oldFont.Size, oldFont.Style, oldFont.Unit) Dim drawBrush As New SolidBrush(WaterMarkColor) args.Graphics.DrawString((If(waterMarkTextEnabled, WaterMarkText, Text)), drawFont, drawBrush, New PointF(0.0F, 0.0F)) MyBase.OnPaint(args) End Sub Private Sub JoinEvents(ByVal join As Boolean) If join Then AddHandler Me.TextChanged, AddressOf WaterMark_Toggle AddHandler Me.LostFocus, AddressOf Me.WaterMark_Toggle AddHandler Me.FontChanged, AddressOf Me.WaterMark_FontChanged End If End Sub Private Sub WaterMark_Toggle(ByVal sender As Object, ByVal args As EventArgs) If Me.Text.Length <= 0 Then EnableWaterMark() Else DisableWaterMark() End If End Sub Private Sub EnableWaterMark() oldFont = New System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit) Me.SetStyle(ControlStyles.UserPaint, True) Me.waterMarkTextEnabled = True Refresh() End Sub Private Sub DisableWaterMark() Me.waterMarkTextEnabled = False Me.SetStyle(ControlStyles.UserPaint, False) If oldFont IsNot Nothing Then Me.Font = New System.Drawing.Font(oldFont.FontFamily, oldFont.Size, oldFont.Style, oldFont.Unit) End If End Sub Private Sub WaterMark_FontChanged(ByVal sender As Object, ByVal args As EventArgs) If waterMarkTextEnabled Then oldFont = New System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit) Refresh() End If End Sub End Class
I attempted to force the class to use my set font size in the OnPaint event, but no luck with that. Is there something else that I am missing that is making this more difficult than it should be?
Thanks!
You’re just missing a Refresh at the end of the DisableWaterMark sub:
EDIT:
Rather than using the UserPaint control style, you can handle the WM_PAINT message in WndProc, and only print the watermark if the text is empty. The result is basically the same though.