0

I have this text box:

<TextBox/>

I want to add a watermark to it to say, Enter your message here...

Since its not supported out of the box, this successfully does the trick:

<Style TargetType="TextBox" xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <Style.Resources>
        <VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
            <VisualBrush.Visual>
                <Label Content="Enter your message here..." Foreground="LightGray" Padding="10 0 0 0" />
            </VisualBrush.Visual>
        </VisualBrush>
    </Style.Resources>
    <Style.Triggers>
        <Trigger Property="Text" Value="{x:Static sys:String.Empty}">
            <Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
        </Trigger>
        <Trigger Property="Text" Value="{x:Null}">
            <Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
        </Trigger>
        <Trigger Property="IsKeyboardFocused" Value="True">
            <Setter Property="Background" Value="White" />
        </Trigger>
    </Style.Triggers>
</Style>

But is there a way to extend TextBox with a XAML property for WatermarkText, as follows and have my style pick it up and use it, or is there some other way to do it (C#, etc.)?

<TextBox WatermarkText="Enter your message here..."/>
Alexandru
  • 12,264
  • 17
  • 113
  • 208
  • If you want to use your current approach, and just have a property to piggy back in the string with. Just replace "Enter your message here..." with `"{TemplateBinding Tag}"` and utilize the `Tag` Property so it would be ` – Chris W. Jun 21 '16 at 15:46
  • 1
    @ChrisW. That should work just fine but I would not be able to further extend my XAML element anymore once I use up my `Tag`. There must be a better way... – Alexandru Jun 21 '16 at 15:47
  • People have done it a number of different ways you can find with a quick google search. Personally last time I needed to I think I just made a custom template with an added TextBlock bound to Tag that on Focus collapsed visibility, and when the text property value ={x:Null} false (with datatrigger) it also collapsed visibility. Didn't take long from what I recall. Like 10mins. – Chris W. Jun 21 '16 at 15:51
  • Wow http://putridparrot.com/blog/basics-of-extending-a-wpf-control/ Exact same problem :) But he had to create a new control that extends `TextBox`. Is that necessary? – Alexandru Jun 21 '16 at 16:02
  • Another option I've thought of is hard-coding two different style resources using `` where `MessageWatermark` contains a hard-coded string itself for example and referencing them `` – Alexandru Jun 21 '16 at 16:13
  • He's creating actual new dependency properties. I never ran into a reason requiring that. It just depends on your specific requirements I suppose. – Chris W. Jun 21 '16 at 16:13
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115221/discussion-between-chris-w-and-alexandru). – Chris W. Jun 21 '16 at 16:14
  • @ChrisW. I went with this in the end: http://stackoverflow.com/questions/37953578/why-is-my-custom-wpf-text-box-control-not-displaying-this-watermark Although, after all that, I would now just recommend programmatically showing and collapsing a label in the same position as the text box in question. – Alexandru Jun 22 '16 at 01:51

2 Answers2

1

The best way to do this is using Attached Dependency Properties that you can bind in the style. Just keep in mind that binding an attached dependency property is

Text={Binding (AttachedPropertyName)}

The () make the trick.

Have a look at Mahapps. It's a nice design framework and providing a TextBoxHelper class doing all this. It's open source so you can see how it is implemented using attached properties.

unkreativ
  • 482
  • 2
  • 8
0

The easiest way to do what I need is to just put a label in the same position as the text box without hit test visibility in the .xaml:

<TextBox Name="Username" Grid.Row="2" Height="40" FontFamily="Segoe UI" FontSize="20" VerticalContentAlignment="Center" TextChanged="Username_TextChanged"/>
<Label Name="UsernameLabel" Content="Username" Grid.Row="2" FontFamily="Segoe UI" FontSize="20" Foreground="LightGray" Padding="5" IsHitTestVisible="False" />

In the .cs:

private void Hostname_TextChanged(object sender, TextChangedEventArgs e)
{
    UpdateLabel(Hostname, HostnameLabel);
}

private void UpdateLabel(TextBox textBox, Label label)
{
    label.Visibility = String.IsNullOrWhiteSpace(textBox.Text) ? Visibility.Visible : Visibility.Hidden;
}

This works for password boxes too, which are sealed, so you cannot inherit them anyways if you tried to extend sealed controls.

Community
  • 1
  • 1
Alexandru
  • 12,264
  • 17
  • 113
  • 208