Zobrazování watermarku v Silverlight

Jan Holan       13. 5. 2013       Silverlight, Komponenty       5233 zobrazení

Pokud se v Silverlight koukneme na kontrol TextBox, zjistíme, že již obsahuje vlastnost Watermark, ta je však bohužel implementována takto:

throw new NotImplementedException();

Pojďme to udělat lépe.

Zavedeme kontrol ExtendedTextBox poděděný z TextBox kontrolu, a v něm založíme novou (pomoci klíčového slova new) dependency property Watermark.

/// <summary>
/// Watermark dependency property
/// </summary>
public new static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(object), typeof(ExtendedTextBox), new PropertyMetadata(OnWatermarkPropertyChanged));

/// <summary>
/// Watermark content
/// </summary>
/// <value>The watermark.</value>
public new object Watermark
{
    get { return (object)GetValue(WatermarkProperty); }
    set { SetValue(WatermarkProperty, value); }
}

V kontrolu dále zavedeme nové stavy pro VisualStateManager - Watermarked a Unwatermarked . Tyto stavy budeme přepínat na událost TextChanged pomoci metody GoToState.

/// <summary>
/// ExtendedTextBox control constructor
/// </summary>
public ExtendedTextBox()
{
    this.DefaultStyleKey = typeof(ExtendedTextBox);
    this.TextChanged += OnTextChanged;
}

private void OnTextChanged(object sender, TextChangedEventArgs e)
{
    SetWatermarkState(true);
}

private void SetWatermarkState(bool useTransitions)
{
    //Update the WatermarkStates group
    if (this.Watermark != null && string.IsNullOrEmpty(this.Text))
    {
        GoToState(this, useTransitions, "Watermarked", "Unwatermarked");
    }
    else
    {
        GoToState(this, useTransitions, "Unwatermarked");
    }
}

private static void GoToState(Control control, bool useTransitions, params string[] stateNames)
{
    if (control == null)
    {
        throw new ArgumentNullException("control");
    }

    if (stateNames != null)
    {
        foreach (string str in stateNames)
        {
            if (VisualStateManager.GoToState(control, str, useTransitions))
            {
                return;
            }
        }
    }
}

Poslední částí řešení bude definovat nový styl pro náš kontrol ExtendedTextBox. Vyjdeme ze standardního stylu pro TextBox, rozšíříme ho o nový VisualStateGroup WatermarkStates a pod ContentElement přidáme ContentControl Watermark.

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="impcontrols:ExtendedTextBox">
            <Grid x:Name="RootElement">
                <VisualStateManager.VisualStateGroups>
                    ...
                    <VisualStateGroup x:Name="WatermarkStates">
                        <VisualStateGroup.Transitions>
                            <VisualTransition GeneratedDuration="0" />
                        </VisualStateGroup.Transitions>
                        <VisualState x:Name="Unwatermarked" />
                        <VisualState x:Name="Watermarked">
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetName="Watermark" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                        
                <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="1" Opacity="1">
                    <Grid>
                        <Border x:Name="ReadOnlyVisualElement" Background="#5EC9C9C9" Opacity="0"/>
                        <Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
                            <ScrollViewer x:Name="ContentElement" BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}"/>
                        </Border>
                        <ContentControl x:Name="Watermark" Opacity="0" IsTabStop="False" IsHitTestVisible="False" Content="{TemplateBinding Watermark}" Foreground="#FF999999" Background="{TemplateBinding Background}" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" FontStyle="{TemplateBinding FontStyle}" FontWeight="{TemplateBinding FontWeight}" Margin="{TemplateBinding Padding}" VerticalAlignment="Top"/>
                    </Grid>
                </Border>
                ...
            </Grid>
        </ControlTemplate>
    </Setter.Value>
</Setter>

Celý kód kontrolu (obsahuje i změny z minula) je dostupný zde ExtendedTextBox.cs a jeho styl zde ExtendedTextBox.xaml.

Obdobně by bylo možné toto řešení převzít i do WPF.

Pokud chceme watermark dodat i pro kontrol PasswordBox, je zde drobný problém v tom, že kontrol PasswordBox je v Silverlight implementován jako sealed, a tak ho nemůžeme podědit. Budeme postupovat jinak. Vlastnost Watermark pro tento kontrol zavedeme jako attached dependency property v nové třídě, kterou nazveme PasswordBoxExtender. Implementace je jinak velice podobná jako v případě TextBoxu. Třídu si můžete prohlédnou zde PasswordBoxExtender.cs.

Také obdobně vytvoříme nový styl pro PasswordBox, ve kterém ale musíme jako Content přidávaného kontrolu ContentControl Watermarku použít odkaz na attached vlastnost:

Content="{TemplateBinding local:PasswordBoxExtender.Watermark}"

Styl je opět dostupný zde PasswordBoxStyles.xaml.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback