Ladislav Ondris Ladislav Ondris - 3 months ago 34
C# Question

How to apply CueBanner for a TextBox in xaml

I want to have a TextBox with CueBanner but it still does not work.
What have I made wrong?
I think the problem is that I am using

{RelativeSource TemplatedParent}
in Resources. How can I do that without putting in Resources?

My xaml code:

<Style TargetType="{x:Type TextBox}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="MinWidth" Value="120" />
<Setter Property="MinHeight" Value="20" />
<Setter Property="AllowDrop" Value="true" />

<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<ControlTemplate.Resources>
<VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}"
Foreground="LightGray" />
</VisualBrush.Visual>
</VisualBrush>
</ControlTemplate.Resources>

<Border x:Name="Border" CornerRadius="0" Padding="2" BorderThickness="1" BorderBrush="Black">
<ScrollViewer Margin="0" x:Name="PART_ContentHost" />
</Border>

<ControlTemplate.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="LightGreen"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>


Thanks for any advice.

EDIT



My problem is solved and here is my final solution:

<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />

<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="Border" CornerRadius="0" Padding="2"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1"
Background="{TemplateBinding Background}">
<Grid>
<ScrollViewer Margin="0" x:Name="PART_ContentHost" />
<TextBlock x:Name="Watermark"
Text="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="LightGray" Margin="5,0" Visibility="Collapsed"/>
</Grid>
</Border>

<ControlTemplate.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Visibility" TargetName="Watermark" Value="Visible" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Visibility" TargetName="Watermark" Value="Visible" />
</Trigger>
<Trigger Property="IsMouseCaptured" Value="True">
<Setter Property="Visibility" TargetName="Watermark" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="Border" Value="0.56"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>

<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="IBeam" />
</Trigger>
</Style.Triggers>
</Style>

Answer

So I wasn't sure what you meant by "CueBanner" at first until I realized it was just synonymous with "Watermark" pretty much. So as a quick example, this would be a quick and easy alternative (since at first glance I don't understand what made that VisualBrush stuff necessary you had in there) made a bit more clean and re-usable though I'm sure you'll want to change the colors I used just for the example. You might also look into something like the Extended Toolkit for some more of this stuff built in, but theirs for example does watermarks differently than this example.

Anyhow, concept example Style template (noticed added the mscorlib namespace in case you don't have it in your res. dict. already for sys:String;

<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>

<Style x:Key="CWWatermarkTextBoxStyle" TargetType="{x:Type TextBox}" 
       xmlns:sys="clr-namespace:System;assembly=mscorlib">
   <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
   <Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
   <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
   <Setter Property="BorderThickness" Value="1"/>
   <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
   <Setter Property="HorizontalContentAlignment" Value="Left"/>
   <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
   <Setter Property="AllowDrop" Value="true"/>
   <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
   <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type TextBox}">
            <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
               <Grid>
                  <ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
                  <TextBlock x:Name="GenericWatermark"
                             Text="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"
                             Foreground="Red" Margin="5,0" Visibility="Collapsed"/>
               </Grid>
            </Border>
         <ControlTemplate.Triggers>
            <Trigger Property="Text" Value="{x:Static sys:String.Empty}">
               <Setter Property="Visibility" TargetName="GenericWatermark" Value="Visible" />
               <Setter Property="Background" Value="Yellow" />
            </Trigger>
            <Trigger Property="IsEnabled" Value="false">
               <Setter Property="Opacity" TargetName="border" Value="0.56"/>
            </Trigger>
            <Trigger Property="IsMouseOver" Value="true">
               <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
            </Trigger>
            <Trigger Property="IsKeyboardFocused" Value="true">
               <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
               <Setter Property="Visibility" TargetName="GenericWatermark" Value="Collapsed"/>
            </Trigger>
         </ControlTemplate.Triggers>
      </ControlTemplate>
   </Setter.Value>
   </Setter>
   <Style.Triggers>
      <MultiTrigger>
         <MultiTrigger.Conditions>
            <Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
            <Condition Property="IsSelectionActive" Value="false"/>
         </MultiTrigger.Conditions>
         <Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
      </MultiTrigger>
   </Style.Triggers>
</Style>

....and usage at the instance example;

<TextBox Tag="HEY LOOK! I'M A TEXTBOX WITH A WATERMARK! WEEEE! :)"
         Style="{StaticResource CWWatermarkTextBoxStyle}"/>

Voila, a quick and simple wpf xaml textbox with watermark. Hope this helps, cheers.