1

I have read this Adding placeholder text to textbox

The problem is, the placeholder TextBox must be easy to reuse. Either with XAML or Code. Maybe it's something like this

<my:TextBoxPlaceholder Placeholder="this is the placeholder"/>

or

<TextBox Placeholder="this is the placeholder"
         Type="/*staticresources*/PlaceholderTextBox"/>

This is what I'm referring to. (the screen shot I got from Instagram Beta).

Imgur Imgur

As you can see, on the second picture, the "Add a comment" placeholder is on the top most of TextBox, it covers the stripe line. Is the placeholder a picture or a TextBlock on top of it?

Community
  • 1
  • 1
Edward Anthony
  • 3,354
  • 3
  • 25
  • 40

3 Answers3

13

You can use the PhoneTextBox control from Windows Phone Toolkit.

It has a Hint property which allows you to set a placeholder:

<toolkit:PhoneTextBox Hint="Add a coment" Text={Binding ...} .../>
anderZubi
  • 6,414
  • 5
  • 37
  • 67
  • 1
    Downside to using the PhoneTextBox is the text goes away when there is keyboard focus – Shawn Kendrot Feb 26 '14 at 16:34
  • I also found this control to be buggy with foreground colors. To repro, do like above, add your hint, F5, enter into the textbox, add text, then hit backspace until no more text, then star typing again, and the text will be gray not black. – PHenry Nov 05 '14 at 03:15
  • Is there a way to keep the hint text when the texbox recieve the focus?? – Cabuxa.Mapache Feb 05 '15 at 09:00
7

The third comment by MacGile on the thread you mentioned shows a fairly simple way to extend the normal TextBox with a special style. If you apply this style on your TextBox, you can use it simply as he illustrates:

<TextBox Style="{StaticResource placeHolder}" 
         Tag="Name of customer" Width="150" Height="24"/>

The Tag attribute is where you enter the placeholder text. The style is designed to change the color according to the text entered and will return to full color black when user edits.

A second way to achieve your goal is to place the TextBox in a Grid and add a TextBlock over it, which you will hide when the TextBlock is not empty (user has entered something). Sample:

<Grid>
   <TextBox x:Name="MyTextBox" />
   <TextBlock Text="enter name..." Foreground="#CCC" 
              Visibility="{Binding ElementName=MyTextBox, Path=Text, Converter={StaticResource StringLengthToVisibilityConverter}}" />
</Grid>

Where the StringLengthToVisibilityConverter is a IValueConverter that returns Visibility.Visible when the string parameter is empty. You can turn this into a custom control or UserControl and it will work just the way you need.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
4

You can accomplish this with a WatermarkTextBox. First create a new class titled WatermarkTextBox.cs

public class WatermarkTextBox : TextBox
{
    public WatermarkTextBox()
    {
        TextChanged += OnTextChanged;    
    }

    private void OnTextChanged(object sender, TextChangedEventArgs textChangedEventArgs)
    {
        // Show or hide the watermark based on the text length
        if (Text.Length > 0)
        {
            WatermarkVisibility = Visibility.Collapsed;
        }
        else
        {
            WatermarkVisibility = Visibility.Visible;
        }
    }

    public string Watermark
    {
        get { return (string)GetValue(WatermarkProperty); }
        set { SetValue(WatermarkProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Watermark.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty WatermarkProperty =
        DependencyProperty.Register("Watermark", typeof(string), typeof(WatermarkTextBox), new PropertyMetadata(null));

    public Visibility WatermarkVisibility
    {
        get { return (Visibility)GetValue(WatermarkVisibilityProperty); }
        set { SetValue(WatermarkVisibilityProperty, value); }
    }

    // Using a DependencyProperty as the backing store for WatermarkVisibility.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty WatermarkVisibilityProperty =
        DependencyProperty.Register("WatermarkVisibility", typeof(Visibility), typeof(WatermarkTextBox), new PropertyMetadata(System.Windows.Visibility.Visible));
}

In your xaml, use this in place of your normal Textbox

<controls:WatermarkTextBox Watermark="Add a comment" Text="{Binding MyProperty}" Style={StaticResource WaterMarkTextBoxStyle/>

Notice the style defined, add the following style to your app.xaml

<Style x:Key="WatermarkTextBoxStyle" TargetType="local: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="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:WatermarkTextBox">
                <Grid Background="Transparent">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver"/>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="MainBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="MainBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="ReadOnly">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="MainBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ReadonlyBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ReadonlyBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ReadonlyBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentElement">
                                        <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="MainBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBackgroundBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="MainBorder">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBorderBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unfocused"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="MainBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}"/>
                    <Border x:Name="ReadonlyBorder" BorderBrush="{StaticResource PhoneDisabledBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Margin="{StaticResource PhoneTouchTargetOverhang}" Visibility="Collapsed"/>
                    <Border BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Margin="{StaticResource PhoneTouchTargetOverhang}">
                        <Grid>
                            <ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="{StaticResource PhoneTextBoxInnerMargin}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch"/>
                            <TextBlock Text="{TemplateBinding Watermark}"  Foreground="Gray" Margin="3,4,0,0" Visibility="{TemplateBinding WatermarkVisibility}"/>
                        </Grid>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Shawn Kendrot
  • 12,425
  • 1
  • 25
  • 41