WPF – Watermark Textbox Behavior


Jeder kennt die schönen Ui’s wo  Eingabecontrols mittels  „Wasserzeichen“ aufgewertet werden. Wenn man ein wenig googelt findet man auch entsprechende Lösungen im Internet. Ich hab das ganze hier im Blog mal wieder als Behavior implementiert und am Ende sieht es dann so aus.

Alles was man dafür im Xaml schreiben muss, ist folgendes:

Im Label wird der anzuzeigende Text angegeben und im LabelStyle kann man das Aussehen des Wasserzeichens ein wenig gestalten.

Das TextBoxWatermark Behavior gestaltet sich relativ simple. Man benötigt 2 Dependency Properties: Label und LabelStyle:

Ich benutze einen einfachen TextBlockAdorner für die Anzeige des Wasserzeichen (Falls jemand einen besseren Adorner mit mehr Gestaltungsmöglichkeiten bei der Hand hat, lasst es mich wissen :)). Im Behavior wird dann zum einen der Load Event der TextBox benutzt und zum anderen der TextChanged Event.

Im TextChanged Event wird die Prüfung für die Anzeige des Wasserzeichen durchgeführt. Für mich war das irgendwie die einzige Möglichkeit im Behavior zu erkennen, ob z.B. mittels Binding sich die Text Eigenschaft geändert hat. Im Load Event wird der TextBlockAdorner angelegt. Ausserdem wird sich für die Änderung von IsFocused der TextBox registriert, da ja bei jedem Focus Wechsel wieder geprüft werden muss, ob man das Wasserzeichen anzeigen soll oder nicht. In meiner 1ten Version hatte ich dafür folgendes benutzt:

Aber damit holt man sich ein MemoryLeak in den Code. Wer das ganze einmal genauer nachlesen will dem sei folgender Post von Adrew Smith ans Herz gelegt. Ich habe den Code einfach übenommen. Die eigentliche Logik ob das Wasserzeichen angezeigt werden soll oder nicht, sieht dann wie folgt aus:

Sobald das Control den Focus hat oder die Text Eigenschaft gefüllt ist wird das Wasserzeichen nicht mehr angezeigt.

Man kann natürlich das ganze auch für eine Combobox oder PasswordBox machen, dazu muss man lediglich beim Behavior den entsprechenden Typ angeben und ggf andere Events beachten.

Download demo source code from here. NOTE: Rename the file extension from .DOC to .ZIP and then decompress it.

Dieser Beitrag wurde unter Behavior - System.Windows.Interactivity abgelegt und mit , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

3 Antworten zu WPF – Watermark Textbox Behavior

  1. Shelah schreibt:

    Very nice, although setting the LabelStyle with HorizontalAlignment and VerticalAlignment causes the banner to dissappear.

    Changing the TextBlockAdorner as follow fixes the problem:

    private readonly TextBlock adornerTextBlock;
    private readonly Size sourceSize;
    public TextBlockAdorner(UIElement adornedElement, string label, Style labelStyle)
    : base(adornedElement)
    {
    adornerTextBlock = new TextBlock { Style = labelStyle, Text = label };
    sourceSize = adornedElement.RenderSize;
    }

    protected override Size MeasureOverride(Size constraint)
    {
    adornerTextBlock.Measure(sourceSize);
    return constraint;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
    adornerTextBlock.Arrange(new Rect(sourceSize));
    return finalSize;
    }

    protected override Visual GetVisualChild(int index)
    {
    return adornerTextBlock;
    }

    protected override int VisualChildrenCount
    {
    get { return 1; }
    }

  2. blindmeis schreibt:

    thx for the info Shelah

  3. Gaurav KP schreibt:

    I found a bug.
    Use this in any wpf grid/ stackpanel. Make the visibility of the grid/stackpanel to true and false.
    You will find that the labels are still visible.
    To solve this issue i had done some change

    //******************** ‚TextBoxWatermarkBehavior‘ needed to be modified ******************

    //**** this is added
    private WeakPropertyChangeNotifier notifierVisibility;

    protected override void OnDetaching()
    {
    base.OnDetaching();
    this.AssociatedObject.Loaded -= this.AssociatedObjectLoaded;
    this.AssociatedObject.TextChanged -= this.AssociatedObjectTextChanged;

    this.notifier = null;
    this.notifierVisibility = null; // **** this is added
    }

    //***** in ‚UpdateAdorner‘ method .. This part is added
    //**** || !this.AssociatedObject.IsVisible
    private void UpdateAdorner()
    {
    if (!String.IsNullOrEmpty(this.AssociatedObject.Text) || this.AssociatedObject.IsFocused || !this.AssociatedObject.IsVisible)
    {
    // Hide the Watermark Label if the adorner layer is visible
    this.AssociatedObject.TryRemoveAdorners();
    }
    else
    {
    // Show the Watermark Label if the adorner layer is visible
    this.AssociatedObject.TryAddAdorner(adorner);
    }
    }

    Now it works fine…. 🙂

Hinterlasse einen Kommentar