Archive
Scratching that old itch.
First of all, I must apologise that it’s been so long since I last blogged. It’s been an insanely busy time for me (and I don’t mean that I’ve been coding with my underpants on my head). As you may be aware, I’m a big fan of Blend behaviours, so I thought that I’d take the time to revisit an old favourite of mine. To that end, I present all the code you’ll need to create a watermarked textbox.
namespace Goldlight.Extensions.Behaviors
{
using System.Windows.Interactivity;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows;
public class WatermarkTextBoxBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.LostFocus += new RoutedEventHandler(LostFocus);
AssociatedObject.GotFocus += new RoutedEventHandler(GotFocus);
SetWatermark();
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.LostFocus -= new RoutedEventHandler(LostFocus);
AssociatedObject.GotFocus -= new RoutedEventHandler(GotFocus);
}
/// <summary>
/// Get or set the brush to use as the foreground.
/// </summary>
public Brush WatermarkForeground { get; set; }
/// <summary>
/// Get or set the brush to use as the background.
/// </summary>
public Brush WatermarkBackground { get; set; }
/// <summary>
/// Get or set the text to apply as the watermark.
/// </summary>
public string WatermarkText { get; set; }
/// <summary>
/// Reset the colours of the textbox.
/// </summary>
private void SetStandard()
{
AssociatedObject.ClearValue(TextBox.ForegroundProperty);
AssociatedObject.ClearValue(TextBox.BackgroundProperty);
if (AssociatedObject.Text == WatermarkText)
{
AssociatedObject.Text = string.Empty;
}
}
/// <summary>
/// Set the watermark colours for the textbox.
/// </summary>
private void SetWatermark()
{
if (WatermarkForeground != null)
{
AssociatedObject.Foreground = WatermarkForeground;
}
if (WatermarkBackground != null)
{
AssociatedObject.Background = WatermarkBackground;
}
AssociatedObject.Text = WatermarkText;
}
void GotFocus(object sender, RoutedEventArgs e)
{
SetStandard();
}
void LostFocus(object sender, RoutedEventArgs e)
{
CheckText(AssociatedObject.Text);
}
private void CheckText(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
SetWatermark();
}
else
{
SetStandard();
}
}
}
}
The code is pretty straightforward. When the textbox receives focus, if it contains just the Watermark text, the watermark text is cleared out and the original foreground and background brushes are restored. When the textbox loses focus, if it’s empty the watermark text is displayed and the watermark fore and background brushes are set. Now, for the clever bit, because we’re updating the textbox text directly we aren’t going to be updating any underlying binding
Watermarked TextBox
Well, I love mucking around in code and I recently decided to see how easy it would be to knock together a user control that would work in both WPF and Silverlight. If you keep it simple, it is really really easy to do. To this end, I present to you the WatermarkTextbox.
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
{
public class WatermarkTextBox : TextBox, INotifyPropertyChanged
{
public WatermarkTextBox()
{
ApplyWatermark();
}
protected virtual void Changed(string propertyName)
{
ApplyWatermark();
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _watermarkText = “Watermark”;
public string WatermarkText
{
get
{
return _watermarkText;
}
set
{
if (_watermarkText != value)
{
if (string.IsNullOrEmpty(Text) || Text == _watermarkText)
{
Text = value;
}
_watermarkText = value;
Changed(“WatermarkText”
}
}
}
private System.Windows.Media.Brush _watermarkForeground = new SolidColorBrush(Colors.LightGray);
public System.Windows.Media.Brush WatermarkForeground
{
get
{
return _watermarkForeground;
}
set
{
if (_watermarkForeground != value)
{
_watermarkForeground = value;
Changed(“WatermarkForeground”
}
}
}
private System.Windows.Media.Brush _watermarkBackground = new SolidColorBrush(Colors.Yellow);
public System.Windows.Media.Brush WatermarkBackground
{
get
{
return _watermarkBackground;
}
set
{
if (_watermarkBackground != value)
{
_watermarkBackground = value;
Changed(“WatermarkBackground”
}
}
}
private System.Windows.Media.Brush _standardForeground = new SolidColorBrush(Colors.Black);
public System.Windows.Media.Brush StandardForeground
{
get
{
return _standardForeground;
}
set
{
if (_standardForeground != value)
{
_standardForeground = value;
Changed(“StandardForeground”
}
}
}
private System.Windows.Media.Brush _standardBackground = new SolidColorBrush(Colors.White);
public System.Windows.Media.Brush StandardBackground
{
get
{
return _standardBackground;
}
set
{
if (_standardBackground != value)
{
_standardBackground = value;
Changed(“StandardBackground”);
}
}
private void
{
Foreground = StandardForeground;
Background = StandardBackground;
}
protected override void OnGotFocus(RoutedEventArgs e)
{
if (Text == WatermarkText)
{
Text = string.Empty;
SetStandard();
}
base
}
protected override void OnLostFocus(RoutedEventArgs e)
{
Text = Text.Trim();
if (Text.Length == 0)
{
ApplyWatermark();
}
base
}
private void ApplyWatermark()
{
if (string.IsNullOrEmpty(Text) || Text == WatermarkText)
{
Text = WatermarkText;
Foreground = WatermarkForeground;
Background = WatermarkBackground;
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
Please feel free to use this class as you like. It comes with no warranty because it’s intended as a proof of concept only. It can do with a tidy up, and it should use Coerce values but I leave that for you to do.



