Hi @Sharp Liverman , Welcome to Microsoft Q&A,
Because UserPaint affects the default way text is drawn, you need to properly let the TextBox handle the text itself, rather than drawing it manually.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace xxx
{
public partial class TextBoxWatermark : TextBox
{
#region Protected Fields
protected string _placeholderText = "Enter text here...";
protected Color _inactivePlaceholderColor = Color.LightGray;
protected Color _focusedPlaceholderColor = Color.Gray;
#endregion
#region Private Fields
private float placeholderOpacity = 0f;
private bool isMouseOver = false;
private Timer fadeTimer;
private Font placeholderFont;
private bool useFocusBehavior = false;
private bool isPlaceholderVisible = true;
#endregion
#region Constructor
public TextBoxWatermark()
{
placeholderFont = this.Font;
this.Multiline = false;
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
this.TextChanged += (s, e) => { CheckPlaceholderVisibility(); };
this.GotFocus += (s, e) => { StartFade(true); };
this.LostFocus += (s, e) => { StartFade(false); };
this.MouseMove += (s, e) =>
{
if (!useFocusBehavior && !isMouseOver)
{
isMouseOver = true;
StartFade(true);
}
};
this.MouseLeave += (s, e) =>
{
if (!useFocusBehavior)
{
isMouseOver = false;
StartFade(false);
}
};
fadeTimer = new Timer();
fadeTimer.Interval = 30;
fadeTimer.Tick += FadeTimer_Tick;
}
#endregion
#region Fade Logic
private void StartFade(bool fadeIn)
{
float target = fadeIn ? 1f : 0f;
if (Math.Abs(placeholderOpacity - target) < 0.1f)
{
placeholderOpacity = target;
fadeTimer.Stop();
}
else
{
fadeTimer.Start();
}
}
private void FadeTimer_Tick(object sender, EventArgs e)
{
float target = (useFocusBehavior ? this.Focused : isMouseOver) ? 1f : 0f;
float step = 0.1f;
if (Math.Abs(placeholderOpacity - target) < step)
{
placeholderOpacity = target;
fadeTimer.Stop();
}
else
{
placeholderOpacity += (placeholderOpacity < target) ? step : -step;
}
this.Invalidate();
}
private void CheckPlaceholderVisibility()
{
isPlaceholderVisible = string.IsNullOrEmpty(this.Text);
this.Invalidate();
}
#endregion
#region Custom Placeholder Drawing
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0xF /* WM_PAINT */ && isPlaceholderVisible)
{
using (Graphics g = Graphics.FromHwnd(this.Handle))
{
Color color = this.Focused ? _focusedPlaceholderColor : _inactivePlaceholderColor;
Color faded = Color.FromArgb((int)(placeholderOpacity * 255), color);
using (Brush b = new SolidBrush(faded))
{
g.DrawString(_placeholderText, placeholderFont, b, new PointF(2f, 2f));
}
}
}
}
#endregion
#region Properties
[Category("Placeholder Settings")]
[Description("The placeholder text that appears when the textbox is empty.")]
public string PlaceholderText
{
get => _placeholderText;
set { _placeholderText = value; this.Invalidate(); }
}
[Category("Placeholder Settings")]
[Description("Color of placeholder when textbox is focused.")]
public Color PlaceholderFocusColor
{
get => _focusedPlaceholderColor;
set { _focusedPlaceholderColor = value; this.Invalidate(); }
}
[Category("Placeholder Settings")]
[Description("Color of placeholder when textbox is not focused.")]
public Color PlaceholderIdleColor
{
get => _inactivePlaceholderColor;
set { _inactivePlaceholderColor = value; this.Invalidate(); }
}
[Category("Placeholder Settings")]
[Description("Font used for placeholder text.")]
public Font PlaceholderFont
{
get => placeholderFont;
set { placeholderFont = value; this.Invalidate(); }
}
[Category("Placeholder Settings")]
[Description("Use focus-based placeholder behavior instead of mouse-over.")]
public bool UseFocusBehavior
{
get => useFocusBehavior;
set
{
useFocusBehavior = value;
fadeTimer.Start();
this.Invalidate();
}
}
#endregion
}
}
Best Regards,
Jiale
If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.