Customizing the WPF DatePicker's Watermark

Introduced as part of the WPF Toolkit and added to .NET 4 as a part of the framework, the DatePicker control is a half-decent replacement for Windows Form's DateTimePicker control.

Something that a lot of people (myself included) don't like about the DatePicker, though, is that by default if no date is displayed it shows the text "Select a date" as a watermark, and this text is baked into the control - it's not localized or accessible by any public property. This is particularly frustrating if the date in question is optional and you don't necessarily want to prompt your users to select one.

There are a few posts around the net describing how to customize this text by deriving your own new control from DatePicker and/or by completely replacing the default ControlTemplate, but this is cumbersome, especially if you already have a project with DatePickers throughout.

Here's a much simpler way to customize the watermark text in a DatePicker.

First, in your app's OnStartup method, you'll want to register a global event handler to the control's Loaded event:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        EventManager.RegisterClassHandler(typeof(DatePicker),
            DatePicker.LoadedEvent, 
            new RoutedEventHandler(DatePicker_Loaded));
    }
}

That means that any DatePicker in our application will call the DatePicker_Loaded method once it's loaded. That method needs to find the watermark text in the control, so we'll need this helper method defined somewhere too:

public static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj == null) return null;

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        var child = VisualTreeHelper.GetChild(depObj, i);

        var result = (child as T) ?? GetChildOfType<T>(child);
        if (result != null) return result;
    }
    return null;
}

Now that we have that in place, our event handler looks like this:

void DatePicker_Loaded(object sender, RoutedEventArgs e)
{
    var dp = sender as DatePicker;
    if (dp == null) return;

    var tb = GetChildOfType<DatePickerTextBox>(dp);
    if (tb == null) return;

    var wm = tb.Template.FindName("PART_Watermark", tb) as ContentControl;
    if (wm == null) return;

    wm.Content = "Your watermark here!";
}

Now all DatePickers will show "Your watermark here!" rather than the default "Select a date" text when no date is selected. If you'd rather not see any watermark at all, simply assign null to wm.Content instead.

wpf datepicker
Posted by: Matt Hamilton
Last revised: 25 Oct, 2014 11:11 AM History

Trackbacks