Prasanna Aarthi
Prasanna Aarthi

Reputation: 3453

Placeholder in windows phone 8 textbox

I need a placeholder in one of my text boxes, I am accomplishing it by have a text with less opacity and placeholder text within the text box, then on focus of text box I am removing the contents of placeholder text and increasing opacity to 1. I have one issue here, In case the user does not enter anything in that field and submits enter, onfocus event is not fired and hence the placeholder text is sent as value for the text box.How do I resolve this?

Upvotes: 1

Views: 3080

Answers (2)

pcnThird
pcnThird

Reputation: 2372

It seems that you're looking for a watermark textbox. You can use an image that displays text in your textbox. That way, you won't be messing with the textbox's data-binding. Read more here: http://msdn.microsoft.com/en-us/library/bb613590(v=vs.110).aspx

I'll update my post soon with an example from one of my older WP projects.

Edit:

Here's the code I used:

    // location is a textbox
    private void location_TextChanged(object sender, TextChangedEventArgs e)
    {
        if (location.Text == "")
        { 
            ImageBrush watermark = new ImageBrush();
            watermark.ImageSource = 
                new BitmapImage(new Uri(@"/Assets/Misc/watermark.png", UriKind.Relative));
            watermark.AlignmentX = AlignmentX.Left;
            watermark.Stretch = Stretch.None;
            watermark.Opacity = .75;
            location.Background = watermark;
        }
        else
        {
            location.Background = new SolidColorBrush(Colors.White);
        }
    }

    private void location_LostFocus(object sender, RoutedEventArgs e)
    {
        location.Background.Opacity = .75;
    }

And here's the (somewhat redundant) textbox XAML:

<TextBox x:Name="location" TextChanged="location_TextChanged" LostFocus="location_LostFocus">
    <TextBox.Background>
        <ImageBrush ImageSource="/Assets/Misc/watermark.png"
                    AlignmentX="Left" Stretch="None"
                    Opacity=".75"/>
    </TextBox.Background>
</TextBox>

And the watermark image looks like this: enter image description here

It took a lot of tweaking to get the image right because you have to consider the appropriate background color, font size, etc.

Perhaps there are better ways of doing this, but I think it's a good starting point.

UPDATE

With Windows Phone 8.1, you can simply use the TextBox's PlaceholderText property

<TextBox PlaceholderText="Enter search query"/>

Upvotes: 2

Farhan Ghumra
Farhan Ghumra

Reputation: 15296

If you don't want to go with image watermark check out below given solutions.

Windows Phone 7 Silverlight Watermark TextBox Control

Windows Phone Watermark TextBox Control

Since link only answers are not valid in SO, I am posting code for 2nd link because I've used that.

WatermarkTextBox.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;

namespace System.Windows.Controls
{
    [StyleTypedProperty(Property = "WatermarkTextStyle", StyleTargetType = typeof(TextBlock)),
    TemplatePart(Name = "WatermarkText", Type = typeof(TextBlock)),
    TemplateVisualState(Name = "WatermarkTextVisible", GroupName = "WatermarkTextStates"),
    TemplateVisualState(Name = "WatermarkTextHidden", GroupName = "WatermarkTextStates")]
    public class WatermarkTextBox : TextBox
    {

        public static readonly DependencyProperty WatermarkTextProperty = DependencyProperty.Register(
            "WatermarkText",
            typeof(string),
            typeof(WatermarkTextBox),
            new PropertyMetadata("", OnWatermarkTextPropertyChanged));

        public static readonly DependencyProperty WatermarkTextForegroundProperty = DependencyProperty.Register(
            "WatermarkTextForeground",
            typeof(Brush),
            typeof(WatermarkTextBox),
            new PropertyMetadata(new SolidColorBrush(Colors.Gray), OnWatermarkTextForegroundPropertyChanged));

        public static readonly DependencyProperty WatermarkTextStyleProperty = DependencyProperty.Register(
            "WatermarkTextStyle",
            typeof(Style),
            typeof(WatermarkTextBox),
            new PropertyMetadata(null, OnWatermarkTextStylePropertyChanged));



        private bool itsIsFocused = false;

        public string WatermarkText
        {
            get { return (string)this.GetValue(WatermarkTextProperty); }
            set { this.SetValue(WatermarkTextProperty, value); }
        }

        public Brush WatermarkTextForeground
        {
            get { return (Brush)this.GetValue(WatermarkTextForegroundProperty); }
            set { this.SetValue(WatermarkTextForegroundProperty, value); }
        }

        public Style WatermarkTextStyle
        {
            get { return (Style)this.GetValue(WatermarkTextStyleProperty); }
            set { this.SetValue(WatermarkTextStyleProperty, value); }
        }



        private static void OnWatermarkTextPropertyChanged(DependencyObject theTarget, DependencyPropertyChangedEventArgs theDependencyPropertyChangedEventArgs)
        {
            // Do nothing
        }

        private static void OnWatermarkTextForegroundPropertyChanged(DependencyObject theTarget, DependencyPropertyChangedEventArgs theDependencyPropertyChangedEventArgs)
        {
            // Do nothing
        }

        private static void OnWatermarkTextStylePropertyChanged(DependencyObject theTarget, DependencyPropertyChangedEventArgs theDependencyPropertyChangedEventArgs)
        {
            // Do nothing
        }



        public WatermarkTextBox()
            : base()
        {
            this.DefaultStyleKey = typeof(WatermarkTextBox);

            this.GotFocus += new RoutedEventHandler(WatermarkTextBox_GotFocus);
            this.LostFocus += new RoutedEventHandler(WatermarkTextBox_LostFocus);
            this.Loaded += new RoutedEventHandler(WatermarkTextBox_Loaded);
            this.TextChanged += new TextChangedEventHandler(WatermarkTextBox_TextChanged);
        }

        private void WatermarkTextBox_Loaded(object sender, RoutedEventArgs e)
        {
            this.GoToVisualState(true);
        }

        private void WatermarkTextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            this.itsIsFocused = true;
            this.GoToVisualState(false);
        }

        private void WatermarkTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            this.itsIsFocused = false;
            this.GoToVisualState(true);
        }

        private void WatermarkTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!this.itsIsFocused)
            {
                this.GoToVisualState(false);
            }
        }

        private void GoToVisualState(bool theIsWatermarkDisplayed)
        {
            if (theIsWatermarkDisplayed && (this.Text == null || (this.Text != null && this.Text.Length == 0)))
            {
                VisualStateManager.GoToState(this, "WatermarkTextVisible", true);
            }
            else
            {
                VisualStateManager.GoToState(this, "WatermarkTextHidden", true);
            }
        }
    }
}

Add style in resource dictionary.

Add xmlns:controls="clr-namespace:System.Windows.Controls;assembly=YOUR_PROJECT_ASSEMBLY_NAME" in <App />

<Style TargetType="controls:WatermarkTextBox">
    <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="WatermarkTextForeground" Value="#FF868686" />
    <Setter Property="WatermarkTextStyle">
        <Setter.Value>
            <Style TargetType="TextBlock">
                <Setter Property="HorizontalAlignment" Value="Left" />
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="Margin" Value="20,0,0,0" />
                <Setter Property="TextWrapping" Value="NoWrap" />
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:WatermarkTextBox">
                <Grid Background="Transparent">
                    <Grid.Resources>
                        <ControlTemplate x:Key="PhoneDisabledTextBoxTemplate" TargetType="controls:WatermarkTextBox">
                            <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
                        </ControlTemplate>
                    </Grid.Resources>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver"/>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="ReadOnly">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="DisabledOrReadonlyBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="DisabledOrReadonlyContent">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxReadOnlyBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="EnabledBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBackgroundBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="EnabledBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBorderBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unfocused"/>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="WatermarkTextStates">
                            <VisualState x:Name="WatermarkTextVisible">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="WatermarkTextBlock" Storyboard.TargetProperty="(UIElement.Opacity)">
                                        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="WatermarkTextHidden">
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="WatermarkTextBlock" Storyboard.TargetProperty="(UIElement.Opacity)">
                                        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="EnabledBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
                        <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
                    </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>
                    <TextBlock x:Name="WatermarkTextBlock" Style="{TemplateBinding WatermarkTextStyle}" Foreground="{TemplateBinding WatermarkTextForeground}" Text="{TemplateBinding WatermarkText}" IsHitTestVisible="False" Grid.ColumnSpan="2" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Usage:

<phone:PhoneApplicationPage 
    xmlns:controls="clr-namespace:System.Windows.Controls"
    .....>

<controls:WatermarkTextBox WatermarkText="Your Watermark Text" />

Upvotes: 3

Related Questions