Alexandru
Alexandru

Reputation: 12922

Using custom properties in WPF styles

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..."/>

Upvotes: 0

Views: 1765

Answers (2)

Alexandru
Alexandru

Reputation: 12922

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.

Upvotes: 0

unkreativ
unkreativ

Reputation: 480

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.

Upvotes: 1

Related Questions