Building a Multiple MonthView DatePicker Control in Silverlight

Building a Multiple MonthView DatePicker Control in Silverlight.


Multiple MonthView DatePicker Control in Silverlight

While working on a project requirement we came across a situation where we needed a date picker supporting a multiple month view. I Googled around and tried to find whether any such solution is available and to my surprise did not found any such thing; may be I am poor in Googling. So I thought, let's dig into this and try my hand at creating a custom control.

Multiple Month View Date Picker

The native date picker comes with a popup that only displays one month at a time but have you seen flight ticket booking websites that show date pickers with a calendar that shows 3 months at time? Something like this:

Month view date picker in silverlight

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, it comes with its own set of calendar and date picker classes written from scratch and we don't want to get involved into thorough testing and also want to avoid any mismatch in the application interface and experience. So I thought, let's do something that exists and modify some properties of the date picker alone to achieve what exactly we want.

The Concept behind

The Date Picker control comes up with a Popup control under System.Windows.Controls.Primitives namespace. Popup controls are bound to a control which can be used to display the content. More details regarding it can be found Here. On editing the Date picker template we can find the PopUp as shown in figure bellow.

popup control in silverlight

Here as the popup contains a calendar control which in turn is used to display the date, to achieve a multiple month view calendar we will clear the existing popup child controls and add our own user control to act as a child control beneath the popup.

So the rest of this article can be divided into the following segments:
  • Creating a Multiple Month View calendar control
  • Creating a templated date picker and using the custom calendar control as a popup

Creating the Custom Multiple Month View calendar user control

Let's add a user control that will act as a popup for a given dropdown control.

silverlight user control

Basically this control will hold 2 calendar controls which will show 3 future months on a selected date. Let me just show you a rough idea of the control placement and clear off intentions.

calander control in silverlight

To achieve the above we will customize the template and apply the CalenderItemStyle. Let's have a look into the template style using blend and make the necessary adjustments.

calender item style in silverlight calender item style property

To hide the individual calendar controls we find the best way to make a button width and height property set to zero.

property of calender control

With the above changes to the style we will create another new calenderItemTemplete style named "CalenderNavButtonDisabled". Let's create a ResourceDictonary and add the preceding template.

style name of control in silverlight

Let's merge this Resource Dictionary to the user control created above.

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="MMVResource.xaml"
/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</UserControl.Resources>

and apply the style to the Calendar controls.

<StackPanel Orientation="Horizontal"
            Grid.Row="1"
            Width="Auto">
    <controls:Calendar Name="Calnder_Main"
                  CalendarItemStyle="{StaticResource CalenderNavButtonDisabled}"
                  DisplayDateChanged="Calnder_Main_DisplayDateChanged"
/>
    <controls:Calendar Name="Calender2"
                  CalendarItemStyle="{StaticResource CalenderNavButtonDisabled}"
                       DisplayDate="8/24/2011"
/>
</StackPanel>

Now on the move we will apply the navigation Button style to the topmost navigation bar. To do that we will add 2 more styles:

navigation button in silverlight

The preceding modification of template style will give us a user control as shown in the figure below:

user control in silverlight

ADDING CODE BEHIND LOGIC TO THE CUSTOM CONTROL

Once the design portion is over we will add some logic to manage the run time behaviour of the control. On the 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 the
Calnder_Main_DisplayDateChanged.

Calendar2.DisplayDate = Calendar_Main.DisplayDate.AddMonths(1);
 
//On Change of Month Change the Display Month and Year of Header Label
var dtf = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat;
string
monthName = dtf.GetMonthName(Calendar_Main.DisplayDate.Month); lblMonth.Content = monthName + "," + Calendar_Main.DisplayDate.Year;

Customizing the Date Picker User Control and Including the User control as popup

As planned, add a templated datepicker control. Choose TemplatedControl template from Visual Studio and let's name it MMVDatePicker.

templated control in silverlight

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 popup and add our user control to the popup. To do that we will collect the popup control with overriding the
OnApplyTempletemethod.

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
 
    //Get the PopUp control of the DatePicker
    this._popup = GetTemplateChild("Popup") as
Popup;
 
    if (this._popup != null)
    {
        this._popup.Opened += new
EventHandler(_popup_Opened); 
    }
}

On opening of the popup the user control will be attached to the date picker.

void _popup_Opened(object sender, EventArgs e)
      {
          //Get the PopUp Canvas
          Canvas popupCanvas = this._popup.Child as
Canvas;
 
          if (popupCanvas != null)
          {
              if
(_ctrl == null)
              {
                  popupCanvas.Children.Clear();
 
                  //Create the Custom multiple month view calender
                  _ctrl = new
CustomPopUpCalender();
                  _ctrl.VerticalAlignment = VerticalAlignment.Stretch;
                  _ctrl.HorizontalAlignment = HorizontalAlignment.Stretch;
                  _ctrl.VerticalContentAlignment = VerticalAlignment.Center;
                  _ctrl.HorizontalContentAlignment = HorizontalAlignment.Center;
 
                  _ctrl.Calendar_Main.SelectedDatesChanged += new EventHandler<SelectionChangedEventArgs>(Calender_SelectedDatesChanged);
                  _ctrl.Calendar2.SelectedDatesChanged += new
EventHandler<SelectionChangedEventArgs>(Calender_SelectedDatesChanged);
                  _popup.LostFocus += new
RoutedEventHandler(ctrl_LostFocus);
 
                  Canvas.SetTop(_ctrl, this.ActualHeight);
 
                  //Add the calender control to the popup
                  popupCanvas.Children.Add(_ctrl);
 
                  Dispatcher.BeginInvoke(() =>
                  {
                      _popup.IsOpen = true;
 
                  });
              }

          }
      }

Well the Dispatcher.Begininvoke is purely to force the UI thread to display the control on the first click.

The Final Control at Run

Calender control in silverlight

Have a look at the control demonstration, live Here.

Conclusion

Let me know if you have any better suggestions or options.

Source code and Live Link

Download Source Code –:
MultipleMonthViewDatePicker

Live Link –: http://manaspatnaik.com/app/MultipleMonthViewCalenderTestPage.html