Home >Backend Development >C++ >How to Implement Disappearing Watermarks in WPF TextBoxes?

How to Implement Disappearing Watermarks in WPF TextBoxes?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2025-01-29 22:56:12963browse

How to Implement Disappearing Watermarks in WPF TextBoxes?

Watermark in Text Boxes

It's possible to include text in a text box that automatically disappears when the user starts typing.

Attached Property Solution

This solution utilizes an attached property to add watermark functionality to any TextBox:

WatermarkService.cs

using System;
using System.Windows;
using System.Windows.Controls;

public static class WatermarkService
{
    public static DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
        "Watermark",
        typeof(object),
        typeof(WatermarkService),
        new FrameworkPropertyMetadata((object)null, OnWatermarkChanged)
    );

    public static object GetWatermark(DependencyObject d)
    {
        return (object)d.GetValue(WatermarkProperty);
    }

    public static void SetWatermark(DependencyObject d, object value)
    {
        d.SetValue(WatermarkProperty, value);
    }

    private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Control control = (Control)d;
        control.Loaded += Control_Loaded;

        if (d is TextBox)
        {
            control.GotKeyboardFocus += Control_GotKeyboardFocus;
            control.LostKeyboardFocus += Control_Loaded;
            ((TextBox)control).TextChanged += Control_GotKeyboardFocus;
        }
    }

    private static void Control_GotKeyboardFocus(object sender, RoutedEventArgs e)
    {
        Control c = (Control)sender;
        if (ShouldShowWatermark(c))
        {
            ShowWatermark(c);
        }
        else
        {
            RemoveWatermark(c);
        }
    }

    private static void Control_Loaded(object sender, RoutedEventArgs e)
    {
        Control control = (Control)sender;
        if (ShouldShowWatermark(control))
        {
            ShowWatermark(control);
        }
    }

    private static void RemoveWatermark(UIElement control)
    {
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);

        if (layer != null)
        {
            Adorner[] adorners = layer.GetAdorners(control);
            if (adorners == null)
            {
                return;
            }

            foreach (Adorner adorner in adorners)
            {
                if (adorner is WatermarkAdorner)
                {
                    adorner.Visibility = Visibility.Hidden;
                    layer.Remove(adorner);
                }
            }
        }
    }

    private static void ShowWatermark(Control control)
    {
        AdornerLayer layer = AdornerLayer.GetAdornerLayer(control);

        if (layer != null)
        {
            layer.Add(new WatermarkAdorner(control, GetWatermark(control)));
        }
    }

    private static bool ShouldShowWatermark(Control c)
    {
        if (c is TextBox)
        {
            return (c as TextBox).Text == string.Empty;
        }
        else
        {
            return false;
        }
    }
}

WatermarkAdorner.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;

internal class WatermarkAdorner : Adorner
{
    private ContentPresenter contentPresenter;

    public WatermarkAdorner(UIElement adornedElement, object watermark) :
       base(adornedElement)
    {
        this.IsHitTestVisible = false;

        this.contentPresenter = new ContentPresenter();
        this.contentPresenter.Content = watermark;
        this.contentPresenter.Opacity = 0.5;
        this.contentPresenter.Margin = new Thickness(Control.Margin.Left + Control.Padding.Left, Control.Margin.Top + Control.Padding.Top, 0, 0);

        // Hide the control adorner when the adorned element is hidden
        Binding binding = new Binding("IsVisible");
        binding.Source = adornedElement;
        binding.Converter = new BooleanToVisibilityConverter();
        this.SetBinding(VisibilityProperty, binding);
    }

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

    private Control Control
    {
        get { return (Control)this.AdornedElement; }
    }

    protected override Visual GetVisualChild(int index)
    {
        return this.contentPresenter;
    }

    protected override Size MeasureOverride(Size constraint)
    {
        this.contentPresenter.Measure(Control.RenderSize);
        return Control.RenderSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        this.contentPresenter.Arrange(new Rect(finalSize));
        return finalSize;
    }
}

Now, add a watermark to any TextBox using this code:

<AdornerDecorator>
    <TextBox x:Name="SearchTextBox">
        <controls:WatermarkService.Watermark>
            <TextBlock>Type here to search text</TextBlock>
        </controls:WatermarkService.Watermark>
    </TextBox>
</AdornerDecorator>

The above is the detailed content of How to Implement Disappearing Watermarks in WPF TextBoxes?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn