1

Reworked Question to clarify my needs:

I want to add a preview Text to Textboxes when they're empty, just like some of you may know it from Xamarin.

I have found this answer on SO.

This is the Style from the Answer I linked above.

<TextBlock Grid.Row="5"
           Grid.Column="1"
           VerticalAlignment="Center"
           Text="Username:">
</TextBlock>
<TextBox Grid.Row="5"
         Grid.Column="3">
    <TextBox.Style>
         <Style TargetType="TextBox">
             <Style.Resources>
                 <VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
                       <VisualBrush.Visual>
                            <Label Content="Test" Foreground="LightGray" />
                       </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>
    </TextBox.Style>
</TextBox>

I get the following result:

enter image description here

Since this is working nicely I want to apply it to every TextBox in that Window. So my approach was to change this line: <Label Content="Test" Foreground="LightGray" />

I thought maybe changing it to <Label Content="Test" Foreground="LightGray" /> would do the trick, but it is not working.

I guess it's something with the Tag Property and the Type of it (object instead of string).

Since the first approach is working like charm I don't really see why I should need a custom control for that...

So what I tried then is this:

 <Window.Resources>
    <Style TargetType="TextBox">
        <Style.Resources>
            <VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
                <VisualBrush.Visual>
                    <Label Content="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" Foreground="LightGray" />
                </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>
</Window.Resources>

What am I missing - why isn't that working ?

Community
  • 1
  • 1
Felix D.
  • 4,811
  • 8
  • 38
  • 72
  • 1
    If you want to use that specific way, just give the Style template an `x:Key` name and place it in a resource dictionary and either set it globally or or use it at the instance like `` – Chris W. Jun 23 '16 at 15:31
  • As Ayyappan Subramanian indicates the binding in the VisualBrush needs some help finding the DataContext. He solves this using his Temp class (e.g. [BindingProxy](http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/)). – Funk Jun 24 '16 at 09:10
  • @Funk so this means it's impossible without a custom control ? - Also note that if there's a completly different solution without a VisualBrush I would like to hear it. – Felix D. Jun 24 '16 at 09:24
  • "why isn't that working ?" because the RelativeSource binding will put the Label's Tag into the Labels Content, you'd want the TextBox's Tag in the Label. But you'll not get that since there's no VisualTree above the Label. – Markus Hütter Jun 25 '16 at 11:54

1 Answers1

2

For the reusable textbox, you need to create a custom control. Also for binding doesnot work well with visual brush, so you need some temp object to store the value. Refer my below code.

 <Window x:Class="ChkList_Learning.Window4"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ChkList_Learning"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="Window4" Height="300" Width="300">
    <Window.Resources>
        <local:Temp x:Key="temp" Value="{Binding ElementName=Hostname, Path=Watermark}"/>
        <Style TargetType="{x:Type local:WatermarkTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
            <Style.Resources>
                <VisualBrush x:Key="WatermarkBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
                    <VisualBrush.Visual>
                        <TextBlock Text="{Binding Source={StaticResource temp}, Path=Value}" FontFamily="Segoe UI" FontSize="20" Foreground="LightGray" Padding="5" />
                    </VisualBrush.Visual>
                </VisualBrush>
            </Style.Resources>
            <Style.Triggers>
                <Trigger Property="Text" Value="{x:Static sys:String.Empty}">
                    <Setter Property="Background" Value="{StaticResource WatermarkBrush}" />
                </Trigger>
                <Trigger Property="Text" Value="{x:Null}">
                    <Setter Property="Background" Value="{StaticResource WatermarkBrush}" />
                </Trigger>
                <Trigger Property="IsKeyboardFocused" Value="True">
                    <Setter Property="Background" Value="White" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <local:WatermarkTextBox x:Name="Hostname" Height="40" FontFamily="Segoe UI" FontSize="20" VerticalContentAlignment="Center" Watermark="Hello, world.">

        </local:WatermarkTextBox>
    </Grid>
</Window>

     public class Temp : Freezable
        {

            // Dependency Property
            public static readonly DependencyProperty ValueProperty =
                 DependencyProperty.Register("Value", typeof(string),
                 typeof(Temp), new FrameworkPropertyMetadata(string.Empty));

            // .NET Property wrapper
            public string Value
            {
                get { return (string)GetValue(ValueProperty); }
                set { SetValue(ValueProperty, value); }
            }

            protected override System.Windows.Freezable CreateInstanceCore()
            {
                return new Temp();
            }
        }
 public class WatermarkTextBox : TextBox
    {
        static WatermarkTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(WatermarkTextBox), new FrameworkPropertyMetadata(typeof(WatermarkTextBox)));
        }

        public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(string), typeof(WatermarkTextBox));

        public string Watermark
        {
            get { return (string)GetValue(WatermarkProperty); }
            set { SetValue(WatermarkProperty, value); }
        }
    }
Ayyappan Subramanian
  • 5,348
  • 1
  • 22
  • 44