Introduction
While working on a project requirement, we came across a situation where we needed a date picker which supports multiple months view. I goggled around and tried to find whether such a solution was available and to my surprise, did not find any. May be I am poor at goggling. :) So I thought if digging into the topic and trying my hand on creating a custom control.
Multiple Months View Date Picker
The native date picker comes with a popup that displays only one month at a time but have you seen flight ticket booking websites that show date pickers with a calendar that shows three months at time? Something like this:
Well, we wanted to achieve the same. We have such controls available from third party vendors such as Telerik and an Open Source project at CodePlex. Although the Open Source CodePlex project does deliver exactly the same functionality, but it comes with its own set of calendar and date picker classes written from scratch, and we didn’t want to get involved into thorough testing, and also wanted to avoid any mismatched in the application interface and experience. So I thought let us build on some thing that exists and modify some properties of the date picker to achieve what exactly we wanted.
The Concept Behind
The date picker control comes with a popup control under the System.Windows.Controls.Primitives
namespace. Popup controls are bound to a control which can be used to display the content. More details regarding this can be found here. On editing the date picker template, we will get a popup as shown in the figure below.
Here the popup contains a calendar control which is in turn used to display the date. To achieve a multiple months view calendar, we will clear the existing popup child controls and add our own user control to act as the child control beneath the popup.
So the rest of article can be divided into the following segments:
- Creating a multiple months view calendar control
- Creating a templated date picker and using the custom calendar control as popup
Creating the Custom Multiple Months View Calendar User Control
Let us add a user control which will act as a popup for a given dropdown control.
Basically, this control will hold two calendar controls which will show three months in advance of a selected date. Let me just show you a rough image of the control placement.
To achieve the above, we will customize the template and will apply the CalenderItemStyle
. Let's have a look at the template style using Blend and make the necessary adjustments.
To hide the individual calendar control, we find the best way to make the button width and height properties set to zero.
With the above changes to the style, we will create another new calenderItemTemplete
style named CalenderNavButtonDisabled
. Let's create a ResourceDictonary
and add the above template.
Let's merge this Resource Dictionary to the User control created above.
and apply the style to the Calendar controls.
Now on the move, we will apply the navigation button style to the topmost navigation bar. For the same, we will add two more styles:
The above modification of the template style will give us a user control as shown in the figure below:
Adding Code-behind Logic to the Custom Control
Once the design portion is over, we will add some logic to manage the runtime behaviour of the control. On month selection changed, for the first calendar, the other one should show the very next month. So we will add the following piece of code to Calnder_Main_DisplayDateChanged
.
Customizing the Date Picker User Control and Including the User Control as a Popup
As planned, add a templated datepicker control. Choose the Templated Control template from Visual Studio and name it MMVDatePicker
.
The date picker class comes with a popup control which in turn holds the default calendar control. The basic idea is to clear the default control from the pop up and add our user control to the popup. To achieve that, we will collect the popup control by overriding the OnApplyTemplate
method.
On opening of the popup, the user control will be attached to the date picker.
Well, Dispatcher.Begininvoke
is purely to force the UI thread to display the control on first click.
The Final Control at Runtime
Have a look at the live control demonstration here.
Conclusion
Let me know if you have any better suggestions or options.