Maybe there is a working solution for this already out there, but I created my own Silverlight Behavior for a basic TextBox Watermark which might be useful.

I wanted to use it like this in my XAML (look at the behaviors tag):

<TextBlock Margin="5">Watermarked textbox:</TextBlock>
<TextBox Margin="5">
    <Interactivity:Interaction.Behaviors>
        <local:Watermark Text="Watermark" Foreground="LightGray" />
    </Interactivity:Interaction.Behaviors>
</TextBox>

The result should be something like this:

To create a Behavior for Silverlight, you must get hold of the System.Windows.Interactivity assembly which ships with Expression Blend. In my system it’s located at:

c:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Silverlight\v4.0\Libraries\System.Windows.Interactivity.dll

And the code for the Behavior:

public class Watermark : Behavior<TextBox>
{
    private bool _hasWatermark;
    private Brush _textBoxForeground;
 
    public String Text { get; set; }
    public Brush Foreground { get; set; }
 
    protected override void OnAttached()
    {
        _textBoxForeground = AssociatedObject.Foreground;
 
        base.OnAttached();
        if (Text != null)
            SetWatermarkText();
        AssociatedObject.GotFocus += GotFocus;
        AssociatedObject.LostFocus += LostFocus;
    }
 
    private void LostFocus(object sender, RoutedEventArgs e)
    {
        if (AssociatedObject.Text.Length == 0)
            if (Text != null)
                SetWatermarkText();
    }
 
    private void GotFocus(object sender, RoutedEventArgs e)
    {
        if (_hasWatermark)
            RemoveWatermarkText();
    }
 
    private void RemoveWatermarkText()
    {
        AssociatedObject.Foreground = _textBoxForeground;
        AssociatedObject.Text = "";
        _hasWatermark = false;
    }
 
    private void SetWatermarkText()
    {
        AssociatedObject.Foreground = Foreground;
        AssociatedObject.Text = Text;
        _hasWatermark = true;
    }
 
    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.GotFocus -= GotFocus;
        AssociatedObject.LostFocus -= LostFocus;
    }
}

Like so many Watermark-solutions out there I’m hooking into the GotFocus/LostFocus events and to the work there. Works for me.