Introduction

This is actually a pretty simple article, and to be honest, I ummed and ahhed about even making this an article at all. I thought it might make a 1/2 decent blog post, but in the end, I thought that it would benefit more people as a published article, so I decided to publish this dead simple article as an article and not a blog post; sorry for its shortness. I know it's not my normal style article, but hope that is OK; I just felt it was useful is all.

So what does the attached code actually do? Well, it is dead simple; it shows you how to modify the standard .NET 4.0 WPF DatePicker control to allow the user to use the keyboard up/down keys to skip days/months/years when the mouse is in the correct portions of the DatePicker text, which is something the standard control does not actually do. It also takes into account any black out dates that may currently be applied, and also shows you how to create a custom Calendar style such that you can place a "Go To Today" button on it.

So that is what we are trying to do. As I say, dead simple, but surprisingly useful, and something that does not come out of the box, and some folk may not know how to do this, so I thought it was worth writing up.

What Does It Look Like

So what does it all look like then? Not surprising, not that interesting, it's a DatePicker which also allows a "Go To Today" button on it. Here it is in all its glory. Freekin ace no (no you say, true code I say).

Here is the Calendar when it is open:

Notice the "Go To Today" button. When the "Go To Today" button is clicked, it will unsurprisingly navigate the Calendar and thus the DatePicker to today's date, unless today's date is one of the black out dates, in which case, the "Go To Today" button will not be enabled.

And here is the Calendar again, but this time, I am showing it with some added black out dates to the Calendar, which you can see are marked as small x's in the image below.

The image shown below shows you something you will have to use a bit of imagination to figure out; basically, if your mouse is over the day part of the date and you press the Up key, the day part of the DatePicker date will increase by one, unless it hits a black out date, in which case, it will advance to the next available non black-out date. The same logic is applied when the Down key is pressed. It works this way for the day/month/year parts.

How Does It All Work

So how does it work then? Well, it's pretty simple, and can be broken down into a few steps:

Step 1: Create a Specialized DatePicker

This step could not be easier; simply inherit from DatePicker, as follows:

publicclass DatePickerEx : DatePicker
{
///<summary>/// Allows us to hook into when a new style is applied, so we can call ApplyTemplate()
/// at the correct time to get the things we need out of the Template
///</summary>publicstaticreadonly DependencyProperty AlternativeCalendarStyleProperty =
DependencyProperty.Register("AlternativeCalendarStyle",
typeof(Style), typeof(DatePickerEx),
new FrameworkPropertyMetadata((Style)null,
new PropertyChangedCallback(OnAlternativeCalendarStyleChanged)));
public Style AlternativeCalendarStyle
{
get { return (Style)GetValue(AlternativeCalendarStyleProperty); }
set { SetValue(AlternativeCalendarStyleProperty, value); }
}
privatestaticvoid OnAlternativeCalendarStyleChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
DatePickerEx target = (DatePickerEx)d;
target.ApplyTemplate();
}
}

We also want our specialized DatePicker to be able to accept a new Style for the Calendar, so that is why we include a new DependencyProperty to allow for this, which in turn allows us to call ApplyTemplate() when we want to. It is basically so we can control when to call ApplyTemplate(), when we know all the required ControlTemplate parts will be available.

Step 2: Create a Calendar Style to Replace the Default One

As we want a "Go To Today" button, we simply create a new Calendar Style in the XAML to support this new button. Here is the full new Style for the Calendar:

Extra Stuff: Showing Tooltips for Blackout Dates

I also decided to show you how to show ToolTips for your blackout dates. To do this, there are a couple of steps.

Step 1: Create an Attached DP Lookup

The first step is to create an attached DP that can be applied firstly to the DatePicker, which will in turn pass the value of this attached DP on to the DatePicker owned Calendar. Here is the attached DP that I conjured up:

See how we apply this attached DP to our specialized DatePicker. How is the Calendar made aware of these? Well, we need to go back a step now and have another look at the ApplyTemplate() method of our specialized DatePicker. The part that ripples the attached DP values from the specialized DatePicker to the Calendar is shown below:

The main things to note here are that there is a ToolTip applied (near the top of the Style), which gets its value through a HighlightDateConverter IValueConverter and that if the HighlightDateConverter IValueConverter value is "{x:Null}" (see the Triggers section above), there is no ToolTip visible.

Step 4: Create the ToolTip

The last peice of the puzzle is to create the ToolTip. This is achived by passing the current date for the Day button and the whole Calendar through a HighlightDateConverter IValueConverter. Where the HighlightDateConverter IValueConverter will see if the current date for the Day button is in Calendar.BlackOutDates range. And if it is found, it will use the found range item to index into the Calendars BlackOutDatesTextLookup attached DP which we setup earlier.

Here is the full listing for the HighlightDateConverter IValueConverter:

"the meat from that butcher is just the dogs danglies, absolutely amazing cuts of beef." - DaveAuld (2011)"No, that is just the earthly manifestation of the Great God Retardon." - Nagy Vilmos (2011)
"It is the celestial scrotum of good luck!" - Nagy Vilmos (2011)

Also I am missing the functionality you describe here in the WPF DatePicker - the Windows Forms equivalent works so well.

Having looked at your code snippets above, I think it won't work for me:
The long date format is dddd, d. MMMM yyyy, parts are not simply separated by a space, and there is the dayname...

And there is another "bug" with the WPF DatePicker: when I change the date by typing without changing the dayname, it throws an exception (invalid date because dayname is not correct). I could overcome that by overriding OnDateValidationError:

Justafewcomments:-Todayisblackedout. Buttonisnotdisabled. WhenIpress ‘Go To Today’, geta ‘System.ArgumentOutOfRangeException’. Articlesaysbuttonisdisabledinasuchcase.
-Ratherthanassumingorderofdd, mm, yyyy, anda ‘/’ separatorabetterideaistosplitusingtheactualtags – theseareinhttp://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.aspx I have just written and published on Codeproject a time control with that logic – it is being so ignored, I am embarrassed!
-MouseWheelisa5minutejobtoimplement. IdidthatwithTimeCtrl.
Otherwise, thankyouforyoursample, whichhaslotofusefulstuffinitandIamgivingyoua5.

Does the keyboard interface I described work with your code when the calendar is open?

Too be honest did not try, so busy. But just checked and yes works fine with my code. I should mention my code assumes UK based date parts, should be easy enough to fix that if you want to use it though

Wieser Software Ltd wrote:

By the way the comment wasn't meant as a criticism, just extra information for people.

I know that, all good do not worry.

Sacha Barber

Microsoft Visual C# MVP 2008-2010

Codeproject MVP 2008-2010

Your best friend is you.
I'm my best friend too. We share the same views, and hardly ever argue