WP7 WatermarkedTextBox custom control
published on: 2/28/2011 | Views: N/A | Tags: CustomControls
by WindowsPhoneGeek
In this article I am going to talk about implementing a Watermarked TextBox custom control in Windows Phone 7.
Basically our WatermarkedTextBox will derive from TextBox and will enable users to add any object element as a Watermark mask. It is actually some kind of extended TextBox that displays a customizable "watermark" whenever its contents are empty and it does not have the focus. Once data is entered in the WatermarkedTextBox input area, the watermark goes away. If the Text value is empty, the watermark displays. As long as data is input the watermark isn't displayed.
The final goal is to build a fully functional and Stylable control with custom logic that can be used in a Silverlight for Windows Phone 7 application.
NOTE: For more information about how to create a Custom Control in Windows Phone 7 check out our previous post "Creating a WP7 Custom Control in 7 Steps". You can also may find interesting the following article:"User Control vs Custom Control in Silverlight for WP7"
Create the basic WatermarkedTextBox prototype
To begin with lets create a Windows Phone 7 Class Library project and follow the 7 steps I described previously. We will create a control called WatermarkedTextBox which derives from TextBox. The basic steps are as follows:
Step 1 - Create the project
Step 2 - Create a WatermarkedTextBox .cs class with the following code:
public class WatermarkedTextBox : TextBox
{
public WatermarkTextBox()
{
DefaultStyleKey = typeof(WatermarkedTextBox);
}
}
Step 3 , Step 4 and Step 5 - Create a generic.xaml file. The structure of our WatermarkedTextBox can be seen on the next schema:
step 6, Step 7 - Create the default ControlTemplate by adding the following code into the generic.xaml.(Note: We will use as a basis the default Style of the WP7 TextBox control and will add some additional elements into it):
<Style TargetType="local:WatermarkedTextBox">
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilyNormal}"/>
<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
<Setter Property="Background" Value="{StaticResource PhoneTextBoxBrush}"/>
<Setter Property="Foreground" Value="{StaticResource PhoneTextBoxForegroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource PhoneTextBoxBrush}"/>
<Setter Property="SelectionBackground" Value="{StaticResource PhoneAccentBrush}"/>
<Setter Property="SelectionForeground" Value="{StaticResource PhoneTextBoxSelectionForegroundBrush}"/>
<Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:WatermarkedTextBox">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
...
</VisualStateManager.VisualStateGroups>
<Border x:Name="EnabledBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
<Grid>
<ContentControl x:Name="watermarkContent" Style="{TemplateBinding WatermarkStyle}" Content="{TemplateBinding Watermark}" Background="Transparent" Opacity="0.5"/>
<ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
</Grid>
</Border>
<Border x:Name="DisabledOrReadonlyBorder" BorderBrush="{StaticResource PhoneDisabledBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Margin="{StaticResource PhoneTouchTargetOverhang}" Visibility="Collapsed">
<TextBox x:Name="DisabledOrReadonlyContent" Background="Transparent" Foreground="{StaticResource PhoneDisabledBrush}"
FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontSize="{TemplateBinding FontSize}"
FontFamily="{TemplateBinding FontFamily}" IsReadOnly="True" SelectionForeground="{TemplateBinding SelectionForeground}"
SelectionBackground="{TemplateBinding SelectionBackground}" TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" Text="{TemplateBinding Text}" Template="{StaticResource PhoneDisabledTextBoxTemplate}" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
NOTE: We use "TemplateBinding" in order to bind properties of the Visual Elments to properties of the control class (i.e.use TemplateBinding in a template to bind to a value on the control the template is applied to).
NOTE: We need to add TemplateBinding to some of the elements and also some "x:Name" attributes.
NOTE: The most important elements in our ControlTemplate are watermarkContent and ContentElement, which represent correspondingly: Watermark and Text properties. The watermarkContent Opacity="0.5".
Add some Custom Properties
NOTE: When creating a custom control you can set a custom dependency DependencyPropertiy default value either in code or in XAML using Style Setters.
For now we will add only two basic dependency properties:
- Watermark - This is a dependency property of type object. It Gets or sets the content displayed as a watermark in the input box when it is empty.
NOTE: The Watermark is typically text that indicates the purpose of the input box. For example, a text box might display the text "Search" until the user enters a search term. But it can be a composite object as well .Any object that derives from UIElement can be used. For example, an empty WatermarkedTextBox might display an image or a TextBlock with customized properties.
- WatermarkStyle - This is a dependency property of type Style. It can ne used to customize the Style of the Watermark element.
The source code is as follows:
public static readonly DependencyProperty WatermarkProperty =
DependencyProperty.Register("Watermark", typeof(object), typeof(WatermarkedTextBox), new PropertyMetadata(OnWatermarkPropertyChanged));
public static readonly DependencyProperty WatermarkStyleProperty =
DependencyProperty.Register("WatermarkStyle", typeof(Style), typeof(WatermarkedTextBox), null);
public Style WatermarkStyle
{
get { return base.GetValue(WatermarkStyleProperty) as Style; }
set { base.SetValue(WatermarkStyleProperty, value); }
}
public object Watermark
{
get { return base.GetValue(WatermarkProperty) as object; }
set { base.SetValue(WatermarkProperty, value); }
}
Another important thing we need to mention the the OnWatermarkPropertyChanged. We will use this property change call back in order to make sure that the every time when the Watermark property changes (including the first time when our control loads) our WatermarkTextBox will show/hide its watermark element in the right way.
private static void OnWatermarkPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
WatermarkedTextBox watermarkTextBox = sender as WatermarkedTextBox;
if(watermarkTextBox != null && watermarkTextBox.WatermarkContent !=null)
{
watermarkTextBox.DetermineWatermarkContentVisibility();
}
}
Overriding OnApplyTemplate
This method is called just before a UI element displays in an application.
NOTE: OnApplyTemplate is often a more appropriate point to deal with adjustments to the template-created visual tree than is the Loaded event. In Silverlight, the Loaded event might occur before the template is applied, and therefore, you might not be able to adjust the visual tree that is created through applying a template in a Loaded handler.
In our case we will override OnApplyTemplate so that we can get a reference to the WatermarkContent element when the template is loaded. We will also call DetermineWatermarkContentVisibility() custom method to determine whether or not to show the Watermark mask. The code is as follows:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.WatermarkContent = this.GetTemplateChild("watermarkContent") as ContentControl;
if(WatermarkContent != null)
{
DetermineWatermarkContentVisibility();
}
}
private void DetermineWatermarkContentVisibility()
{
if (string.IsNullOrEmpty(this.Text))
{
this.WatermarkContent.Visibility = Visibility.Visible;
}
else
{
this.WatermarkContent.Visibility = Visibility.Collapsed;
}
}
Defining WatermarkedTextBox behavior
The next thing to do is to determine the behavior of our control. At first we will override OnGotFocus and OnLostFocus handlers. Basically in OnLostFocus we will show the WatermarkContent if the WatermarkedTextBox is focused and its Text value is null or empty. In OnGotFocus we will hide the WatermarkContent . The source code is as follows:
protected override void OnGotFocus(RoutedEventArgs e)
{
if (WatermarkContent != null && string.IsNullOrEmpty(this.Text))
{
this.WatermarkContent.Visibility = Visibility.Collapsed;
}
base.OnGotFocus(e);
}
protected override void OnLostFocus(RoutedEventArgs e)
{
if (WatermarkContent != null && string.IsNullOrEmpty(this.Text))
{
this.WatermarkContent.Visibility = Visibility.Visible;
}
base.OnLostFocus(e);
}
Examples:
We will create a sample Windows Phone 7 application project that will be used in order to test the newly created WatermarkedTextBox control. So add reference to the control assembly(WatermarkTextBoxControl.dll) and add the following code in MainPage.xaml:
NOTE: To use the WatermarkedTextBox in the XAML you have to add the following namespace declaration:
xmlns:watermark="clr-namespace:WatermarkedTextBoxControl;assembly=WatermarkedTextBoxControl"
1. Simple usage:
<watermark:WatermarkedTextBox Watermark="Password"/>
2. Usage with custom style:
<phone:PhoneApplicationPage.Resources>
<Style x:Key="styleRed" TargetType="ContentControl">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="FontSize" Value="40"/>
<Setter Property="Foreground" Value="Red"/>
</Style>
</phone:PhoneApplicationPage.Resources>
<watermark:WatermarkedTextBox Watermark="Password" WatermarkStyle="{StaticResource styleRed}"/>
3. Advanced usage:
<phone:PhoneApplicationPage.Resources>
<Style x:Key="styleGreen" TargetType="ContentControl">
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground" Value="Green"/>
</Style>
</phone:PhoneApplicationPage.Resources>
<watermark:WatermarkedTextBox WatermarkStyle="{StaticResource styleGreen}" x:Name="text">
<watermark:WatermarkedTextBox.Watermark>
<StackPanel Orientation="Horizontal">
<Image Source="logo.png" Stretch="None"/>
<TextBlock Text="Enter Password"/>
</StackPanel>
</watermark:WatermarkedTextBox.Watermark>
</watermark:WatermarkedTextBox>
4. Creating WatermarkedTextBox programmatically:
WatermarkedTextBox textBox = new WatermarkedTextBox(); textBox.Watermark = "Test Watermark"; this.ContentPanel.Children.Add(textBox);
That was all about how to implement a WatermarkedTextBox in Windows Phone 7. You can find the full source code (class library and sample test project) here:
I hope that the article was helpful.
You can also follow us on Twitter @winphonegeek
Comments
Just
posted by: Atley on 3/1/2011 6:55:28 AM
This is a great tutorial. Using text boxes like this can really add a professional style to your phone apps!!!
I think that every WP7 developer should check this article out! Nicely done!
Good + keyboard transparency
posted by: Jhon on 3/4/2011 12:01:43 AM
very nice :) enjoyable!!!!
Also can you suggest me about keyboard theme, I want to change the background and foreground. But It's always black. Is there any api or way to do the same.
thanks in advance!!!
RE:Good + keyboard transparency
posted by: windowsphonegeek on 3/4/2011 2:36:34 PM
You can not change the background and foreground of the wp7 keyboard because the SIP is not a real Silverlight control so lacks the benefits of such things like theming.
However you can implement your own custom keyboard but the main disadvantage here is that you will have to handle the whole SIP functionality on your own.
RE:Good + keyboard transparency
posted by: Jhon on 3/4/2011 4:14:26 PM
Many thanks for your suggestion. Will try it. :)
Use with Prism
posted by: Arkady on 3/30/2011 1:56:14 PM
Hi,
When i put
<prismInteractivity:UpdateTextBindingOnPropertyChanged/>
into the WaterMarketTexbox Behaviors list when i click to space button, cursor in texbox moves to very beginning...
Any workaround about this issue?
Regards,
Use with Prism
posted by: Arkady on 3/30/2011 2:07:17 PM
Sorry, was my bug. Control works just great.
Thanks!
Included in Mango?
posted by: thnk2wn on 5/27/2011 6:41:46 AM
FYI: Looks like Watermark support is built-in now with 7.1: http://screencast.com/t/QaHduiKH
how do we print * s in password box
posted by: neo on 6/22/2011 12:58:43 PM
how do we print * s in password box when user types password?
RE: how do we print * s in password box
posted by: Jonathan on 11/10/2011 6:18:09 PM
@neo - You can use the Password inputscope for textboxes.
A Small Bug
posted by: Mike on 5/1/2012 5:13:15 AM
Nice control. Seems to have an issue. If you bind the control to a string that has a text value to it and the enabled flag is bound to a boolean value. Have the control initially disabled when it come up then change the boolean so the box become enabled. You will have the text value and the watermark simultaneously intil you give the control focus.
TextBox Control in Windows Phone 7 Development
posted by: Ankit Singh on 5/12/2012 5:08:52 PM
Hi,
I was reading your article and I would like to appreciate you for making it very simple and understandable. This article gives me a basic idea of TextBox control in widows phone development. There are some good articles too which also explained very well about windows phone 7 development textbox control. For more details on that post please check out this links...
TextBox Control in Windows 7 Phone Development.......DZON TextBox Control in Windows 7 Phone Development
Thanks for wonderful post it really helpful for beginner as well as developer.
Our Top Articles & Free books
- Our FREE e-book: "Windows Phone Toolkit In Depth" 2nd edition
- 400+ Windows Phone Development articles in our Article Index
- 21 WP7 Toolkit in Depth articles covering all controls
- 12 WP7 Coding4Fun Toolkit in Depth articles covering all controls
- Performance Tips when creating WP7 apps
- Creating a WP7 Custom Control in 7 Steps
- WP7 working with VisualStates: How to make a ToggleSwitch from CheckBox
- What makes a WP7 App successful
- Creating theme friendly UI in WP7 using OpacityMask
- Implementing Windows Phone 7 DataTemplateSelector and CustomDataTemplateSelector
- All about Splash Screens in WP7 – Creating animated Splash Screen
- Getting Started with Unit Testing in Silverlight for WP7
- WP7 WatermarkedTextBox custom control
Our Top Tips & Samples
- All about WP7 Isolated Storage series
- WP7 Dynamically Generating DataTemplate in code
- 5 tips for a successful WP7 Marketplace submission
- WP7: Navigating to a page in different assembly
- WP7 ContextMenu: answers to popular questions
- WP7 ListBox: answers to popular questions
- WP7 working with Images: Content vs Resource build action
- WP7 Element Binding samples
- WP7 working with XML: reading, filtering and databinding
- Drawing in WP7: #2 Drawing shapes with finger
- WP7 TextBox Light theme problems - the solution
- Changing the WP7 Panorama Background Image dynamically with Animation
