One of the great disappointments of a programmer’s workday is creating a component only to discover shortly after finishing that someone else had already created the exact same component. Happened to me the other day. Literally 30 minutes after quietly putting together a DevExpress DateEdit that only displayed years and months, I hear a coworker say, “Hey, does anyone remember what assembly that DevExpress YearMonth DateEdit lives in?”

Me: “Funny that you should ask, I just finished creating one.”

Him: “Why? We already have one…”

Me: “You sure? I checked in assembly xyz where all the UI components are kept.”

[pause]

Him: “…yep, just found it. It’s in this other assembly, which also has some UI components.”

Me: (pouting silently)

I was mostly annoyed because of the lost time, most of which was spent figuring out how exactly to tweak the DateEdit the way I wanted. Which leads me to this post. Even though there are DevExpress support posts which explain how to do this (here and here, for example), it took me a while to locate them. Maybe I hadn’t had enough coffee yet that morning, maybe my googling skills are just lacking, who knows, but I decided to post the completed component figuring I might make the solution easier to find.

I did make one additional modification. As shown below, I overrode ShowToday in the YearMonthRepositoryItemDateEdit to always return false and hide it from the designer properties grid. This was because clicking the link for “today” results in the days of the month being shown which, obviously, is what we’re trying to avoid. The class definition in its entirety is below:

using System;
using System.ComponentModel;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Calendar;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Popup;
using DevExpress.XtraEditors.Repository;

namespace WindowsFormsApplication1
{
    public class MonthYearEdit : DateEdit
    {
        public MonthYearEdit()
        {
            Properties.Mask.EditMask = "y";
        }

        protected override PopupBaseForm CreatePopupForm()
        {
            return new YearMonthVistaPopupDateEditForm(this);
        }

        protected override void CreateRepositoryItem()
        {
            fProperties = new YearMonthRepositoryItemDateEdit(this);
        }

        class YearMonthRepositoryItemDateEdit : RepositoryItemDateEdit
        {
            public YearMonthRepositoryItemDateEdit(DateEdit dateEdit)
            {
                SetOwnerEdit(dateEdit);
            }

            [Browsable(false)]
            public override bool ShowToday
            {
                get
                {
                    return false;
                }
            }
        }

        class YearMonthVistaPopupDateEditForm : VistaPopupDateEditForm
        {
            public YearMonthVistaPopupDateEditForm(DateEdit ownerEdit)
                : base(ownerEdit) { }

            protected override DateEditCalendar CreateCalendar()
            {
                return new YearMonthVistaDateEditCalendar(OwnerEdit.Properties,
                    OwnerEdit.EditValue);
            }
        }

        class YearMonthVistaDateEditCalendar : VistaDateEditCalendar
        {
            public YearMonthVistaDateEditCalendar(RepositoryItemDateEdit item,
                object editDate) : base(item, editDate) { }

            protected override void Init()
            {
                base.Init();
                View = DateEditCalendarViewType.YearInfo;
            }

            protected override void OnItemClick(CalendarHitInfo hitInfo)
            {
                DayNumberCellInfo cell = (DayNumberCellInfo)hitInfo.HitObject;

                if (View == DateEditCalendarViewType.YearInfo)
                {
                    DateTime date = new DateTime(DateTime.Year, cell.Date.Month, 1);
                    OnDateTimeCommit(date, false);
                }
                else
                {
                    base.OnItemClick(hitInfo);
                }
            }
        }
    }
}