Leggendo il minicorso di ScottGu non ho potuto fare a meno di  notare come SilverLight 2.0 nasca già con dei controlli che tutt'ora mancano in WPF come, ad esempio, la WatermarkedTextBox. Ho deciso quindi di crearmi un alternativa per full WPF.
Ho creato un controllo WatermakedTextBox ereditando da TextBox e aggiungendo una DependencyProperty Watermark

public class WatermarkedTextBox:TextBox
{
    #region Watermark

    /// <summary>
    /// Watermark Dependency Property
    /// </summary>
    public static readonly DependencyProperty WatermarkProperty =
            DependencyProperty.Register("Watermark", typeof(string), typeof(WatermarkedTextBox),
                    new FrameworkPropertyMetadata("Topic..."));

    /// <summary>
    /// Gets or sets the Watermark property.
    /// </summary>
    public string Watermark
    {
        get { return (string)GetValue(WatermarkProperty); }
        set { SetValue(WatermarkProperty, value); }
    }

    #endregion        
}

Fatto questo ho modificato i trigger che agiscono sul template associato alla textbox, per recuperare lo xaml corrispondente ho usato la possibilità di creare una copia dello stile associato ad un controllo messa a disposizione da Expression Blend nel menu Object.

image

Lo xaml, piuttosto lunghetto, è questo:

<Window.Resources>
    <LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" StartPoint="0,0" MappingMode="Absolute">
        <GradientStop Color="#ABADB3" Offset="0.05"/>
        <GradientStop Color="#E2E3EA" Offset="0.07"/>
        <GradientStop Color="#E3E9EF" Offset="1"/>
    </LinearGradientBrush>
    <Style x:Key="WatermarkedTextBoxStyle1" BasedOn="{x:Null}" TargetType="{x:Type local:WatermarkedTextBox}">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
        <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="AllowDrop" Value="true"/>
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:WatermarkedTextBox}">
                    <Microsoft_Windows_Themes:ListBoxChrome SnapsToDevicePixels="true" x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding IsMouseOver}">
                        <!--Added a grid to host both elements-->
                        <Grid>
                            <ScrollViewer SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" x:Name="PART_ContentHost" />
                            <!--This textblock is bound to watermark property will display watermark text-->
                            <TextBlock Visibility="Collapsed" x:Name="waterMark" Text="{TemplateBinding Watermark}" Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>                            
                        </Grid>
                    </Microsoft_Windows_Themes:ListBoxChrome>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                        <!--These triggers swap between watermark and text editing--> 
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsFocused" Value="False" />
                                <Condition Property="Text" Value="" />
                            </MultiTrigger.Conditions>
                            <MultiTrigger.Setters>
                                <Setter Property="Visibility" Value="Visible" TargetName="waterMark" />
                                <Setter Property="Visibility" Value="Collapsed" TargetName="PART_ContentHost" />
                            </MultiTrigger.Setters>
                        </MultiTrigger>
                        <Trigger Property="IsFocused" Value="True">
                            <Setter Property="Visibility" Value="Collapsed" TargetName="waterMark" />
                            <Setter Property="Visibility" Value="Visible" TargetName="PART_ContentHost" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

Ho modificato il tempate ospitando sia lo scrollviewer che il texblock che visualizzerà il watermark in una griglia e aggiungendo un paio di MultiTrigger che regolano la visibilità del watermark e del normale contenuto della textbox.

Tha's all!, per usare il nuovo controllo basta scrivere:

<Grid>
        <local:WatermarkedTextBox  Height="24" Margin="62,74,84,0" VerticalAlignment="Top" 
                                                             Style="{DynamicResource WatermarkedTextBoxStyle1}" />
</Grid>

per ottenere la texbox con la realita modalità "Watermark"

 

Technorati Tags: ,