Introduction

This project contains watermark solutions for the TextBox and the PasswordBox. There is a WatermarkTextBox in the Extended WPF Toolkit, there is (to date) no solution for the PasswordBox. Also, I prefer to keep my projects as light as possible, so here is a very simple solution to a commonly requested pair of controls.

 

 

Building the Sample

Just download, unblock, unzip, load & run!

 

Description

The purpose of a watermark is to convey a message behind the control. In the case of this demonstration, the watermark also dissappear after you start typing text, so they are more like a field "hint" telling you what is expected.

 

To achieve this, we turn to a regular WPF solution provider, the AttachedProperty. AttachedProperties allow you to add extra properties to any control. You can also extend it into an Attachedbehaviour, where you are making the control react to changes to the property.

 

In this example, we use two attached properties. The first "WaterrmarkProperty" to take the watermark value and initialise the control:

C#
Edit|Remove
public static string GetWatermark(DependencyObject obj) 
{ 
    return (string)obj.GetValue(WatermarkProperty); 
} 
 
public static void SetWatermark(DependencyObject obj, string value) 
{ 
    obj.SetValue(WatermarkProperty, value); 
} 
 
public static readonly DependencyProperty WatermarkProperty = 
    DependencyProperty.RegisterAttached("Watermark"typeof(string), typeof(TextBoxHelper), new UIPropertyMetadata(null, WatermarkChanged));

The second attached property is to notify whether there is a value in the box, which the template binds to and hides or shows the watermark.

 

C#
Edit|Remove
public static bool GetShowWatermark(DependencyObject obj) 
{ 
    return (bool)obj.GetValue(ShowWatermarkProperty); 
} 
 
public static void SetShowWatermark(DependencyObject obj, bool value) 
{ 
    obj.SetValue(ShowWatermarkProperty, value); 
} 
 
public static readonly DependencyProperty ShowWatermarkProperty = 
    DependencyProperty.RegisterAttached("ShowWatermark"typeof(bool), typeof(TextBoxHelper), new UIPropertyMetadata(false));
 

For the TextBoxHelper, whenever the text is changed, the watermark is shown or hidden as follows:

 

 

C#
Edit|Remove
private static void CheckShowWatermark(TextBox box) 
{ 
    box.SetValue(TextBoxHelper.ShowWatermarkProperty, box.Text == string.Empty); 
} 
This is controlled by the ControlTemplate:
XAML
Edit|Remove
<ControlTemplate x:Key="WatermarkedTextBoxTemplate" TargetType="{x:Type TextBox}"> 
    <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true"> 
        <Grid> 
            <TextBlock Text="{Binding Path=(local:TextBoxHelper.Watermark), RelativeSource={RelativeSource TemplatedParent}}" Opacity=".5" FontWeight="Bold" Visibility="{Binding (local:TextBoxHelper.ShowWatermark), Converter={StaticResource BooleanToVisibilityConverter}, RelativeSource={RelativeSource TemplatedParent}}" /> 
            <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
        </Grid> 
    </Microsoft_Windows_Themes:ListBoxChrome> 
    <ControlTemplate.Triggers> 
        <Trigger Property="IsEnabled" Value="false"> 
            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> 
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> 
        </Trigger> 
    </ControlTemplate.Triggers> 
</ControlTemplate>

 

 

Source Code Files