public class WatermarkedTextBox : DependencyObject
{
#region Fields
private const string _defaultWatermark = "None" ;
public static readonly DependencyProperty WatermarkTextProperty = DependencyProperty.Register( "WatermarkText" , typeof ( string ), typeof (WatermarkedTextBox), new UIPropertyMetadata( string .Empty, OnWatermarkTextChanged));
#endregion
#region Constructor(s)
/// <summary>
/// Initializes a new instance of the <see cref="WatermarkedTextBox"/> class with default watermark text.
/// </summary>
public WatermarkedTextBox()
: this (_defaultWatermark)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WatermarkedTextBox"/> class.
/// </summary>
/// <param name="watermark">The watermark to show when value is <c>null</c> or empty.</param>
public WatermarkedTextBox( string watermark)
{
WatermarkText = watermark;
}
#endregion
#region Properties
public string WatermarkText
{
get { return ( string )GetValue(WatermarkTextProperty); }
set { SetValue(WatermarkTextProperty, value ); }
}
#endregion
#region Methods
public static void OnWatermarkTextChanged(DependencyObject box, DependencyPropertyChangedEventArgs e)
{
//Add changed functionality here
}
#endregion
}
* This source code was highlighted with Source Code Highlighter .
Now that the procurement has been created and we have the necessary properties and methods of operating with a hint, we can proceed directly to the implementation. On the move you can come up with many options for implementation:TextBox
, write logic and make your own data mapping.TextBox
(instead of DependencyObject
).The ControlTemplate for a TextBox must contain the content element; this element will be used to render the contents of the textbox. Assign it to the special name PART_ContentHost. The ScrollViewer or An AdornerDecorator. The host element may not be any child elements.This means that in the template you will need to create a ScrollViewer with the name PART_ContentHost.
TextBox
missing - we will show the prepared inscription from a separate TextBlock
, otherwise we will pretend to be a normal TextBox
.< TextBlock x:Name ="WatermarkText" Text ="{TemplateBinding WatermarkText}" Foreground ="Gray" Margin ="5,0,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Center" Visibility ="Collapsed" IsHitTestVisible ="False" />
* This source code was highlighted with Source Code Highlighter .
I added a few beauties in the form of indents and colors to make the effort more noticeable.< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="{x:Null}" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
* This source code was highlighted with Source Code Highlighter .
They will provide us with a text of the tooltip at a time when the value in the text field is missing and the field is in a state other than the input state. Unfortunately, you have to write two almost identical triggers so that string .Empty and null are processed equally well.< Style TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" BasedOn ="{StaticResource {x:Type TextBox}}" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" >
< Grid >
< ScrollViewer x:Name ="PART_ContentHost" />
< TextBlock x:Name ="WatermarkText" Text ="{TemplateBinding WatermarkText}" Foreground ="Gray" Margin ="5,0,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Center" Visibility ="Collapsed" IsHitTestVisible ="False" />
</ Grid >
< ControlTemplate.Triggers >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="{x:Null}" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
</ ControlTemplate.Triggers >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
* This source code was highlighted with Source Code Highlighter .
Neatly connected all the parts, added to the style of the page. Theoretically, you can already shout cheers and stomp your feet in ecstasy, but if you run the application, it turns out that the frame is somewhere gone. We will try to restore this injustice by wrapping the grid.< Style TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" BasedOn ="{StaticResource {x:Type TextBox}}" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" >
< Border Background ="{TemplateBinding Background}" BorderBrush ="{TemplateBinding BorderBrush}" BorderThickness ="{TemplateBinding BorderThickness}" >
< Grid >
< ScrollViewer x:Name ="PART_ContentHost" />
< TextBlock x:Name ="WatermarkText" Text ="{TemplateBinding WatermarkText}" Foreground ="Gray" Margin ="5,0,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Center" Visibility ="Collapsed" IsHitTestVisible ="False" />
</ Grid >
</ Border >
< ControlTemplate.Triggers >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="{x:Null}" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
</ ControlTemplate.Triggers >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
* This source code was highlighted with Source Code Highlighter .
Now the work is completed. You can enjoy the result. Or download a working example .Source: https://habr.com/ru/post/71151/
All Articles