WPF Toolkit DatePicker Month/Year Only

Viewed 54476

I'm using the Toolkit's Datepicker as above but I'd like to restrict it to month and year selections only, as in this situation the users don't know or care about the exact date .Obviously with the data being stored in a Datetime format there will be day stored but that doesn't concern me. Is there an easy way to tie this down?

Thanks

7 Answers

Recently I had a specific requirement for calendar with the option to choose only month and year. So i have a previous post about custom format for the wpf datepicker, but in this case we need to do a little tricky answer. First you need to create a specific control like this:

public class DatePickerCo : DatePicker

Once you have already do this. Exists another post when someone else, I don't rememberer the url for that post, but anyway, the think is you need to overwrite the OnCalendarOpened method just like this:

 
 protected override void OnCalendarOpened(RoutedEventArgs e)
        {
            var popup = this.Template.FindName(
                "PART_Popup", this) as Popup;
            if (popup != null && popup.Child is System.Windows.Controls.Calendar)
            {
                ((System.Windows.Controls.Calendar)popup.Child).DisplayMode = CalendarMode.Year;
            }

            ((System.Windows.Controls.Calendar)popup.Child).DisplayModeChanged += new EventHandler(DatePickerCo_DisplayModeChanged);
        }

Notice that we add a last line with the handler for the event DisplayModeChanged. This is really important for the next steps. Ok so the next step is define the DisplayModeChanged


 private void DatePickerCo_DisplayModeChanged(object sender, CalendarModeChangedEventArgs e)
        {
            var popup = this.Template.FindName(
                "PART_Popup", this) as Popup;
            if (popup != null && popup.Child is System.Windows.Controls.Calendar)
            {
                var _calendar = popup.Child as System.Windows.Controls.Calendar;
                if (_calendar.DisplayMode == CalendarMode.Month)
                {
                    _calendar.DisplayMode = CalendarMode.Year;

                    if (IsDropDownOpen)
                    {
                        this.SelectedDate = GetSelectedMonth(_calendar.DisplayDate);
                        this.IsDropDownOpen = false;
                        ((System.Windows.Controls.Calendar)popup.Child).DisplayModeChanged -= new EventHandler(DatePickerCo_DisplayModeChanged);
                    }
                }

            }
        }

 private DateTime? GetSelectedMonth(DateTime? selectedDate)
        {
            if (selectedDate == null)
            {
                selectedDate = DateTime.Now;
            }

            int monthDifferenceStart = DateTimeHelper.CompareYearMonth(selectedDate.Value, DisplayDateRangeStart);
            int monthDifferenceEnd = DateTimeHelper.CompareYearMonth(selectedDate.Value, DisplayDateRangeEnd);

            if (monthDifferenceStart >= 0 && monthDifferenceEnd  0, "monthDifferenceEnd should be greater than 0!");
                    _selectedMonth = DateTimeHelper.DiscardDayTime(DisplayDateRangeEnd);
                }
            }

            return _selectedMonth;
        }

Here there's a couple things, first you need to pick a month, so thats the reason for create the function GetSelectedMonth. The second thing is that method use a class of the WPFToolkit called DateTimeHelper.cs. Ok Until now we just created the functionality for pick up the month. But once you have click on the month calendar, we proceed to show the selected date in month/year format. For accomplish that we just need to create a specific style to our custom control like this:

In my first answer How to change format (e.g. dd/MMM/yyyy) of DateTimePicker in WPF application

I explained all about with the custom format of the date picker. I hope this help you. please any comment or suggestion, you just let me know, regards!!.

I want to provide an alternative solution that doesn't require a lot of code. You can bind to a DatePickers's CalendarOpened event. In that event you can set the display mode of the Calendar to Decade and add an event handler for the DisplayModeChanged event on the Calendar. Then in the DisplayModeChanged event handler you can close the calendar if the mode is month, and also set the SelectedDate to the current DisplayDate. This has worked well for my purposes

XAML

<DatePicker
Name="YearPicker"
Grid.Column="1"
SelectedDate="{Binding SelectedDate, Mode=TwoWay}"
CalendarOpened="DatePicker_Opened">
<DatePicker.Resources>
    <Style TargetType="DatePickerTextBox">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <TextBox x:Name="PART_TextBox"
                            Text="{Binding Path=SelectedDate, StringFormat = {}{0:MM-yyyy}, 
                            RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}}" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</DatePicker.Resources>

Then for the code behind

private void DatePicker_Opened(object sender, RoutedEventArgs e)
{
    DatePicker datepicker = (DatePicker)sender;
    Popup popup = (Popup)datepicker.Template.FindName("PART_Popup", datepicker);
    Calendar cal = (Calendar)popup.Child;
    cal.DisplayModeChanged += Calender_DisplayModeChanged;
    cal.DisplayMode = CalendarMode.Decade;
}

private void Calender_DisplayModeChanged(object sender, CalendarModeChangedEventArgs e)
{
    Calendar calendar = (Calendar)sender;
    if (calendar.DisplayMode == CalendarMode.Month)
    {
        calendar.SelectedDate = calendar.DisplayDate;
        YearPicker.IsDropDownOpen = false;
    }
}

I hope this helps!

Related