Introduction
To download the source code for this project, please
click here.
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 the source code from here, unblock, unzip, load in Visual Studio & run!
Description
The purpose of a watermark is to convey a message behind the control. In the case of this demonstration, the watermark also disappear 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 "WatermarkProperty" to take the watermark value and initialize the control:
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.
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:
private
static
void
CheckShowWatermark(TextBox box)
{
box.SetValue(TextBoxHelper.ShowWatermarkProperty, box.Text ==
string
.Empty);
}
<
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
>
Please visit my MSDN Samples pages to download more projects, or click here to
download this project.