Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / WinForms / Managed / System / WinForms / MonthCalendar.cs / 1 / MonthCalendar.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* */ namespace System.Windows.Forms { using System.Runtime.Serialization.Formatters; using System.Runtime.Remoting; using System.Runtime.InteropServices; using System.Diagnostics; using System; using System.Security.Permissions; using System.Globalization; using System.Windows.Forms.Internal; using System.ComponentModel; using System.ComponentModel.Design; using ArrayList = System.Collections.ArrayList; using System.Drawing; using Microsoft.Win32; using System.Windows.Forms.Layout; ////// /// This control is an encapsulateion of the Windows month calendar control. /// A month calendar control implements a calendar-like user interface, that /// provides the user with a very intuitive and recognizable method of entering /// or selecting a date. /// Users can also select which days bold. The most efficient way to add the /// bolded dates is via an array all at once. (The below descriptions can be applied /// equally to annually and monthly bolded dates as well) /// The following is an example of this: /// [ ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch), DefaultProperty("SelectionRange"), DefaultEvent("DateChanged"), DefaultBindingProperty("SelectionRange"), Designer("System.Windows.Forms.Design.MonthCalendarDesigner, " + AssemblyRef.SystemDesign), SRDescription(SR.DescriptionMonthCalendar) ] public class MonthCalendar : Control { const long DAYS_TO_1601 = 548229; const long DAYS_TO_10000 = 3615900; static readonly Color DEFAULT_TITLE_BACK_COLOR = SystemColors.ActiveCaption; static readonly Color DEFAULT_TITLE_FORE_COLOR = SystemColors.ActiveCaptionText; static readonly Color DEFAULT_TRAILING_FORE_COLOR = SystemColors.GrayText; private const int MINIMUM_ALLOC_SIZE = 12; // minimum size to expand the buffer by private const int MONTHS_IN_YEAR = 12; ////// MonthCalendar mc = new MonthCalendar(); /// // add specific dates to bold /// DateTime[] time = new DateTime[3]; /// time[0] = DateTime.Now; /// time[1] = time[0].addDays(2); /// time[2] = time[1].addDays(2); /// mc.setBoldedDates(time); ///
/// Removal of all bolded dates is accomplished with: ////// mc.removeAllBoldedDates(); ///
/// Although less efficient, the user may need to add or remove bolded dates one at /// a time. To improve the performance of this, neither addBoldedDate nor /// removeBoldedDate repaints the monthcalendar. The user must call updateBoldedDates /// to force the repaint of the bolded dates, otherwise the monthCalendar will not /// paint properly. /// The following is an example of this: ////// DateTime time1 = new DateTime("3/5/98"); /// DateTime time2 = new DateTime("4/19/98"); /// mc.addBoldedDate(time1); /// mc.addBoldedDate(time2); /// mc.removeBoldedDate(time1); /// mc.updateBoldedDates(); ///
/// The same applies to addition and removal of annual and monthly bolded dates. ////// /// This is the arbitrary number of pixels that the Win32 control /// inserts between calendars horizontally, regardless of font. /// ///private const int INSERT_WIDTH_SIZE = 6; /// /// /// This is the arbitrary number of pixels that the Win32 control /// inserts between calendars vertically, regardless of font. /// ///private const int INSERT_HEIGHT_SIZE = 6; // From comctl32 MonthCalendar sources CALBORDER private const Day DEFAULT_FIRST_DAY_OF_WEEK = Day.Default; private const int DEFAULT_MAX_SELECTION_COUNT = 7; private const int DEFAULT_SCROLL_CHANGE = 0; private const int UNIQUE_DATE = 0; private const int ANNUAL_DATE = 1; private const int MONTHLY_DATE = 2; private static readonly Size DefaultSingleMonthSize = new Size(176, 153); private const int MaxScrollChange = 20000; private const int ExtraPadding = 2; private IntPtr mdsBuffer = IntPtr.Zero; private int mdsBufferSize = 0; // styles private Color titleBackColor = DEFAULT_TITLE_BACK_COLOR; private Color titleForeColor = DEFAULT_TITLE_FORE_COLOR; private Color trailingForeColor = DEFAULT_TRAILING_FORE_COLOR; private bool showToday = true; private bool showTodayCircle = true; private bool showWeekNumbers = false; private bool rightToLeftLayout = false; // properties private Size dimensions = new Size(1, 1); private int maxSelectionCount = DEFAULT_MAX_SELECTION_COUNT; // VSWhidbey 400284: Reconcile out-of-range min/max values in the property getters. private DateTime maxDate = DateTime.MaxValue; private DateTime minDate = DateTime.MinValue; private int scrollChange = DEFAULT_SCROLL_CHANGE; private bool todayDateSet = false; // Has TodayDate been explicitly set? private DateTime todayDate = DateTime.Now.Date; private DateTime selectionStart; private DateTime selectionEnd; private Day firstDayOfWeek = DEFAULT_FIRST_DAY_OF_WEEK; /// /// /// Bitmask for the annually bolded dates. Months start on January. /// ///private int[] monthsOfYear = new int[12]; /// /// /// Bitmask for the dates bolded monthly. /// ///private int datesToBoldMonthly = 0; /// /// /// Lists are slow, so this section can be optimized. /// Implementation is such that inserts are fast, removals are slow. /// ///private ArrayList arrayOfDates = new ArrayList(); private ArrayList annualArrayOfDates = new ArrayList(); // we have to maintain these lists too. private ArrayList monthlyArrayOfDates = new ArrayList(); // notifications private DateRangeEventHandler onDateChanged; private DateRangeEventHandler onDateSelected; private EventHandler onRightToLeftLayoutChanged; /// /// /// Creates a new MonthCalendar object. Styles are the default for a /// regular month calendar control. /// public MonthCalendar() : base() { selectionStart = todayDate; selectionEnd = todayDate; SetStyle(ControlStyles.UserPaint, false); SetStyle(ControlStyles.StandardClick, false); TabStop = true; } ////// /// The array of DateTime objects that determines which annual days are shown /// in bold. /// [ Localizable(true), SRDescription(SR.MonthCalendarAnnuallyBoldedDatesDescr) ] public DateTime[] AnnuallyBoldedDates { get { DateTime[] dateTimes = new DateTime[annualArrayOfDates.Count]; for (int i=0;i < annualArrayOfDates.Count; ++i) { dateTimes[i] = (DateTime)this.annualArrayOfDates[i]; } return dateTimes; } set { // this.annualArrayOfDates.Clear(); for (int i=0; i0) { //add each boldeddate to our ArrayList... for (int i = 0; i < value.Length; i++) { this.annualArrayOfDates.Add(value[i]); } for (int i = 0; i < value.Length; ++i) { monthsOfYear[value[i].Month-1] |= 0x00000001<<(value[i].Day-1); } } RecreateHandle(); } } /// /// /// [SRDescription(SR.MonthCalendarMonthBackColorDescr)] public override Color BackColor { get { if (ShouldSerializeBackColor()) { return base.BackColor; } else { return SystemColors.Window; } } set { base.BackColor = value; } } ///[To be supplied.] ////// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override Image BackgroundImage { get { return base.BackgroundImage; } set { base.BackgroundImage = value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageChanged { add { base.BackgroundImageChanged += value; } remove { base.BackgroundImageChanged -= value; } } /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageLayoutChanged { add { base.BackgroundImageLayoutChanged += value; } remove { base.BackgroundImageLayoutChanged -= value; } } /// /// /// The array of DateTime objects that determines which non-recurring /// specified dates are shown in bold. /// /*Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),*/ [Localizable(true)] public DateTime[] BoldedDates { get { DateTime[] dateTimes = new DateTime[arrayOfDates.Count]; for (int i=0;i < arrayOfDates.Count; ++i) { dateTimes[i] = (DateTime)this.arrayOfDates[i]; } return dateTimes; } set { // this.arrayOfDates.Clear(); if (value != null && value.Length > 0) { //add each boldeddate to our ArrayList... for (int i = 0; i < value.Length; i++) { this.arrayOfDates.Add(value[i]); } } RecreateHandle(); } } ////// /// The number of columns and rows of months that will be displayed /// in the MonthCalendar control. /// [ SRCategory(SR.CatAppearance), Localizable(true), SRDescription(SR.MonthCalendarDimensionsDescr) ] public Size CalendarDimensions { get { return dimensions; } set { if (!this.dimensions.Equals(value)) SetCalendarDimensions(value.Width, value.Height); } } ////// /// This is called when creating a window. Inheriting classes can ovveride /// this to add extra functionality, but should not forget to first call /// base.getCreateParams() to make sure the control continues to work /// correctly. /// protected override CreateParams CreateParams { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] get { CreateParams cp = base.CreateParams; cp.ClassName = NativeMethods.WC_MONTHCAL; cp.Style |= NativeMethods.MCS_MULTISELECT | NativeMethods.MCS_DAYSTATE; if (!showToday) cp.Style |= NativeMethods.MCS_NOTODAY; if (!showTodayCircle) cp.Style |= NativeMethods.MCS_NOTODAYCIRCLE; if (showWeekNumbers) cp.Style |= NativeMethods.MCS_WEEKNUMBERS; if (RightToLeft == RightToLeft.Yes && RightToLeftLayout == true) { //We want to turn on mirroring for Form explicitly. cp.ExStyle |= NativeMethods.WS_EX_LAYOUTRTL; //Don't need these styles when mirroring is turned on. cp.ExStyle &= ~(NativeMethods.WS_EX_RTLREADING | NativeMethods.WS_EX_RIGHT | NativeMethods.WS_EX_LEFTSCROLLBAR); } return cp; } } ///protected override ImeMode DefaultImeMode { get { return ImeMode.Disable; } } /// protected override Padding DefaultMargin { get { return new Padding(9); } } /// protected override Size DefaultSize { get { return GetMinReqRect(); } } /// /// /// This property is overridden and hidden from statement completion /// on controls that are based on Win32 Native Controls. /// [EditorBrowsable(EditorBrowsableState.Never)] protected override bool DoubleBuffered { get { return base.DoubleBuffered; } set { base.DoubleBuffered = value; } } ////// /// The first day of the week for the month calendar control. /// [ SRCategory(SR.CatBehavior), Localizable(true), DefaultValue(DEFAULT_FIRST_DAY_OF_WEEK), SRDescription(SR.MonthCalendarFirstDayOfWeekDescr) ] public Day FirstDayOfWeek { get { return firstDayOfWeek; } set { //valid values are 0x0 to 0x7 if (!ClientUtils.IsEnumValid(value, (int)value, (int)Day.Monday, (int)Day.Default)){ throw new InvalidEnumArgumentException("FirstDayOfWeek", (int)value, typeof(Day)); } if (value != firstDayOfWeek) { firstDayOfWeek = value; if (IsHandleCreated) { if (value == Day.Default) { RecreateHandle(); } else { SendMessage(NativeMethods.MCM_SETFIRSTDAYOFWEEK, 0, (int) value); } } } } } ////// /// [SRDescription(SR.MonthCalendarForeColorDescr)] public override Color ForeColor { get { if (ShouldSerializeForeColor()) { return base.ForeColor; } else { return SystemColors.WindowText; } } set { base.ForeColor = value; } } ///[To be supplied.] ///[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public ImeMode ImeMode { get { return base.ImeMode; } set { base.ImeMode = value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler ImeModeChanged { add { base.ImeModeChanged += value; } remove { base.ImeModeChanged -= value; } } /// /// /// The maximum allowable date that can be selected. By default, there /// is no maximum date. The maximum date is not set if max less than the /// current minimum date. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarMaxDateDescr) ] public DateTime MaxDate { get { return DateTimePicker.EffectiveMaxDate(maxDate); } set { if (value != maxDate) { if (value < DateTimePicker.EffectiveMinDate(minDate)) { throw new ArgumentOutOfRangeException("MaxDate", SR.GetString(SR.InvalidLowBoundArgumentEx, "MaxDate", FormatDate(value), "MinDate")); } maxDate = value; SetRange(); } } } ////// /// The maximum number of days that can be selected in a /// month calendar control. This method does not affect the current /// selection range. /// [ SRCategory(SR.CatBehavior), DefaultValue(DEFAULT_MAX_SELECTION_COUNT), SRDescription(SR.MonthCalendarMaxSelectionCountDescr) ] public int MaxSelectionCount { get { return maxSelectionCount; } set { if (value < 1) { throw new ArgumentOutOfRangeException("MaxSelectionCount", SR.GetString(SR.InvalidLowBoundArgumentEx, "MaxSelectionCount", (value).ToString("D", CultureInfo.CurrentCulture), (1).ToString(CultureInfo.CurrentCulture))); } if (value != maxSelectionCount) { if (IsHandleCreated) { if ((int)SendMessage(NativeMethods.MCM_SETMAXSELCOUNT, value, 0) == 0) throw new ArgumentException(SR.GetString(SR.MonthCalendarMaxSelCount, (value).ToString("D", CultureInfo.CurrentCulture)), "MaxSelectionCount"); } maxSelectionCount = value; } } } ////// /// The minimum allowable date that can be selected. By default, there /// is no minimum date. The minimum date is not set if min greater than the /// current maximum date. MonthCalendar does not support dates prior to 1753. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarMinDateDescr) ] public DateTime MinDate { get { return DateTimePicker.EffectiveMinDate(minDate); } set { if (value != minDate) { if (value > DateTimePicker.EffectiveMaxDate(maxDate)) { throw new ArgumentOutOfRangeException("MinDate", SR.GetString(SR.InvalidHighBoundArgument, "MinDate", FormatDate(value), "MaxDate")); } // If trying to set the minimum less than DateTimePicker.MinimumDateTime, throw // an exception. if (value < DateTimePicker.MinimumDateTime) { throw new ArgumentOutOfRangeException("MinDate", SR.GetString(SR.InvalidLowBoundArgumentEx, "MinDate", FormatDate(value), FormatDate(DateTimePicker.MinimumDateTime))); } minDate = value; SetRange(); } } } ////// /// The array of DateTime objects that determine which monthly days to bold. /// [ Localizable(true), SRDescription(SR.MonthCalendarMonthlyBoldedDatesDescr) ] public DateTime[] MonthlyBoldedDates { get { DateTime[] dateTimes = new DateTime[monthlyArrayOfDates.Count]; for (int i=0;i < monthlyArrayOfDates.Count; ++i) { dateTimes[i] = (DateTime)this.monthlyArrayOfDates[i]; } return dateTimes; } set { // this.monthlyArrayOfDates.Clear(); datesToBoldMonthly = 0; if (value != null && value.Length > 0) { //add each boldeddate to our ArrayList... for (int i = 0; i < value.Length; i++) { this.monthlyArrayOfDates.Add(value[i]); } for (int i = 0; i < value.Length; ++i) { datesToBoldMonthly |= 0x00000001<<(value[i].Day-1); } } RecreateHandle(); } } ////// /// ///private DateTime Now { get { return DateTime.Now.Date; } } /// /// /// [ Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public new Padding Padding { get { return base.Padding; } set { base.Padding = value;} } [ Browsable(false), EditorBrowsable(EditorBrowsableState.Never) ] public new event EventHandler PaddingChanged { add { base.PaddingChanged += value; } remove { base.PaddingChanged -= value; } } ////// ///[To be supplied.] ////// /// This is used for international applications where the language /// is written from RightToLeft. When this property is true, // and the RightToLeft is true, mirroring will be turned on on the form, and /// control placement and text will be from right to left. /// [ SRCategory(SR.CatAppearance), Localizable(true), DefaultValue(false), SRDescription(SR.ControlRightToLeftLayoutDescr) ] public virtual bool RightToLeftLayout { get { return rightToLeftLayout; } set { if (value != rightToLeftLayout) { rightToLeftLayout = value; using(new LayoutTransaction(this, this, PropertyNames.RightToLeftLayout)) { OnRightToLeftLayoutChanged(EventArgs.Empty); } } } } ////// /// The scroll rate for a month calendar control. The scroll /// rate is the number of months that the control moves its display /// when the user clicks a scroll button. If this value is zero, /// the month delta is reset to the default, which is the number of /// months displayed in the control. /// [ SRCategory(SR.CatBehavior), DefaultValue(DEFAULT_SCROLL_CHANGE), SRDescription(SR.MonthCalendarScrollChangeDescr) ] public int ScrollChange { get { return scrollChange; } set { if (scrollChange != value) { if (value < 0) { throw new ArgumentOutOfRangeException("ScrollChange", SR.GetString(SR.InvalidLowBoundArgumentEx, "ScrollChange", (value).ToString("D", CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); } if (value > MaxScrollChange) { throw new ArgumentOutOfRangeException("ScrollChange", SR.GetString(SR.InvalidHighBoundArgumentEx, "ScrollChange", (value).ToString("D", CultureInfo.CurrentCulture), (MaxScrollChange).ToString("D", CultureInfo.CurrentCulture))); } if (IsHandleCreated) { SendMessage(NativeMethods.MCM_SETMONTHDELTA, value, 0); } scrollChange = value; } } } ////// /// [ SRCategory(SR.CatBehavior), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarSelectionEndDescr) ] public DateTime SelectionEnd { get { return selectionEnd; } set { if (selectionEnd != value) { // Keep SelectionEnd within min and max if (value < MinDate) { throw new ArgumentOutOfRangeException("SelectionEnd", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionEnd", FormatDate(value), "MinDate")); } if (value > MaxDate) { throw new ArgumentOutOfRangeException("SelectionEnd", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionEnd", FormatDate(value), "MaxDate")); } // If we've moved SelectionEnd before SelectionStart, move SelectionStart back if (selectionStart > value) { selectionStart = value; } // If we've moved SelectionEnd too far beyond SelectionStart, move SelectionStart forward if ((value - selectionStart).Days >= maxSelectionCount) { selectionStart = value.AddDays(1 - maxSelectionCount); } // Set the new selection range SetSelRange(selectionStart, value); } } } ///Indicates the end date of the selected range of dates. ////// /// [ SRCategory(SR.CatBehavior), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarSelectionStartDescr) ] public DateTime SelectionStart { get { return selectionStart; } set { if (selectionStart != value) { // Keep SelectionStart within min and max // if (value < minDate) { throw new ArgumentOutOfRangeException("SelectionStart", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionStart", FormatDate(value), "MinDate")); } if (value > maxDate) { throw new ArgumentOutOfRangeException("SelectionStart", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionStart", FormatDate(value), "MaxDate")); } // If we've moved SelectionStart beyond SelectionEnd, move SelectionEnd forward if (selectionEnd < value) { selectionEnd = value; } // If we've moved SelectionStart too far back from SelectionEnd, move SelectionEnd back if ((selectionEnd - value).Days >= maxSelectionCount) { selectionEnd = value.AddDays(maxSelectionCount - 1); } // Set the new selection range SetSelRange(value, selectionEnd); } } } ////// Indicates /// the start date of the selected range of dates. ////// /// Retrieves the selection range for a month calendar control. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarSelectionRangeDescr), Bindable(true) ] public SelectionRange SelectionRange { get { return new SelectionRange(SelectionStart, SelectionEnd); } set { SetSelectionRange(value.Start, value.End); } } ////// /// Indicates whether the month calendar control will display /// the "today" date at the bottom of the control. /// [ SRCategory(SR.CatBehavior), DefaultValue(true), SRDescription(SR.MonthCalendarShowTodayDescr) ] public bool ShowToday { get { return showToday; } set { if (showToday != value) { showToday = value; UpdateStyles(); AdjustSize(); } } } ////// /// Indicates whether the month calendar control will circle /// the "today" date. /// [ SRCategory(SR.CatBehavior), DefaultValue(true), SRDescription(SR.MonthCalendarShowTodayCircleDescr) ] public bool ShowTodayCircle { get { return showTodayCircle; } set { if (showTodayCircle != value) { showTodayCircle = value; UpdateStyles(); } } } ////// /// Indicates whether the month calendar control will the display /// week numbers (1-52) to the left of each row of days. /// [ SRCategory(SR.CatBehavior), Localizable(true), DefaultValue(false), SRDescription(SR.MonthCalendarShowWeekNumbersDescr) ] public bool ShowWeekNumbers { get { return showWeekNumbers; } set { if (showWeekNumbers != value) { showWeekNumbers = value; UpdateStyles(); AdjustSize(); } } } ////// /// The minimum size required to display a full month. The size /// information is presented in the form of a Point, with the x /// and y members representing the minimum width and height required /// for the control. The minimum required window size for a month calendar /// control depends on the currently selected font. /// [ SRCategory(SR.CatAppearance), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarSingleMonthSizeDescr) ] public Size SingleMonthSize { get { NativeMethods.RECT rect = new NativeMethods.RECT(); if (IsHandleCreated) { if ((int)SendMessage(NativeMethods.MCM_GETMINREQRECT, 0, ref rect) == 0) throw new InvalidOperationException(SR.GetString(SR.InvalidSingleMonthSize)); return new Size(rect.right, rect.bottom); } return DefaultSingleMonthSize; } } ////// /// Unlike most controls, serializing the MonthCalendar's Size is really bad: /// when it's restored at runtime, it uses a a default SingleMonthSize, which /// may not be right, especially for JPN/CHS machines. See VSWhidbey 527753. /// [ DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false) ] public new Size Size { get { return base.Size; } set { base.Size = value; } } ////// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override string Text { get { return base.Text; } set { base.Text = value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler TextChanged { add { base.TextChanged += value; } remove { base.TextChanged -= value; } } /// /// /// The date shown as "Today" in the Month Calendar control. /// By default, "Today" is the current date at the time /// the MonthCalendar control is created. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarTodayDateDescr) ] public DateTime TodayDate { get { if (todayDateSet) return todayDate; if (IsHandleCreated) { NativeMethods.SYSTEMTIME st = new NativeMethods.SYSTEMTIME(); int res = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_GETTODAY, 0, st); Debug.Assert(res != 0, "MCM_GETTODAY failed"); return DateTimePicker.SysTimeToDateTime(st).Date; } else return Now.Date; } set { if (!(todayDateSet) || (DateTime.Compare(value, todayDate) != 0)) { // throw if trying to set the TodayDate to a value greater than MaxDate if (DateTime.Compare(value, maxDate) > 0) { throw new ArgumentOutOfRangeException("TodayDate", SR.GetString(SR.InvalidHighBoundArgumentEx, "TodayDate", FormatDate(value), FormatDate(maxDate))); } // throw if trying to set the TodayDate to a value less than MinDate if (DateTime.Compare(value, minDate) < 0) { throw new ArgumentOutOfRangeException("TodayDate", SR.GetString(SR.InvalidLowBoundArgument, "TodayDate", FormatDate(value), FormatDate(minDate))); } todayDate = value.Date; todayDateSet = true; UpdateTodayDate(); } } } ////// /// Indicates whether or not the TodayDate property has been explicitly /// set by the user. If TodayDateSet is true, TodayDate will return whatever /// the user has set it to. If TodayDateSet is false, TodayDate will follow /// wall-clock time; ie. TodayDate will always equal the current system date. /// [ SRCategory(SR.CatBehavior), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarTodayDateSetDescr) ] public bool TodayDateSet { get { return todayDateSet; } } ////// /// The background color displayed in the month calendar's /// title. /// [ SRCategory(SR.CatAppearance), SRDescription(SR.MonthCalendarTitleBackColorDescr) ] public Color TitleBackColor { get { return titleBackColor; } set { if (value.IsEmpty) { throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "value")); } titleBackColor = value; SetControlColor(NativeMethods.MCSC_TITLEBK, value); } } ////// /// The foreground color used to display text within the month /// calendar's title. /// [ SRCategory(SR.CatAppearance), SRDescription(SR.MonthCalendarTitleForeColorDescr) ] public Color TitleForeColor { get { return titleForeColor; } set { if (value.IsEmpty) { throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "value")); } titleForeColor = value; SetControlColor(NativeMethods.MCSC_TITLETEXT, value); } } ////// /// The color used to display the previous and following months that /// appear on the current month calendar. /// [ SRCategory(SR.CatAppearance), SRDescription(SR.MonthCalendarTrailingForeColorDescr) ] public Color TrailingForeColor { get { return trailingForeColor; } set { if (value.IsEmpty) { throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "value")); } trailingForeColor = value; SetControlColor(NativeMethods.MCSC_TRAILINGTEXT, value); } } ////// /// Adds a day that will be bolded annually on the month calendar. /// Be sure to call updateBoldedDates() afterwards. /// public void AddAnnuallyBoldedDate(DateTime date) { annualArrayOfDates.Add(date); monthsOfYear[date.Month-1] |= 0x00000001<<(date.Day-1); } ////// /// Adds a day that will be bolded on the month calendar. /// Be sure to call updateBoldedDates() afterwards. /// public void AddBoldedDate(DateTime date) { if (!this.arrayOfDates.Contains(date)) { this.arrayOfDates.Add(date); } } ////// /// Adds a day that will be bolded monthly on the month calendar. /// Be sure to call updateBoldedDates() afterwards. /// public void AddMonthlyBoldedDate(DateTime date) { this.monthlyArrayOfDates.Add(date); datesToBoldMonthly |= 0x00000001<<(date.Day-1); } ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler Click { add { base.Click += value; } remove { base.Click -= value; } } /// /// /// [SRCategory(SR.CatAction), SRDescription(SR.MonthCalendarOnDateChangedDescr)] public event DateRangeEventHandler DateChanged { add { onDateChanged += value; } remove { onDateChanged -= value; } } ///[To be supplied.] ////// /// [SRCategory(SR.CatAction), SRDescription(SR.MonthCalendarOnDateSelectedDescr)] public event DateRangeEventHandler DateSelected { add { onDateSelected += value; } remove { onDateSelected -= value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler DoubleClick { add { base.DoubleClick += value; } remove { base.DoubleClick -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event MouseEventHandler MouseClick { add { base.MouseClick += value; } remove { base.MouseClick -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event MouseEventHandler MouseDoubleClick { add { base.MouseDoubleClick += value; } remove { base.MouseDoubleClick -= value; } } /// /// /// MonthCalendar Onpaint. /// ///[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event PaintEventHandler Paint { add { base.Paint += value; } remove { base.Paint -= value; } } /// /// /// [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftLayoutChangedDescr)] public event EventHandler RightToLeftLayoutChanged { add { onRightToLeftLayoutChanged += value; } remove { onRightToLeftLayoutChanged -= value; } } ///[To be supplied.] ////// /// Used to auto-size the control. The requested number of rows and columns are /// restricted by the maximum size of the parent control, hence the requested number /// of rows and columns may not be what you get. /// ///private void AdjustSize() { Size minSize = GetMinReqRect(); Size = minSize; } /// /// /// Event handler that bolds dates indicated by arrayOfDates /// ///private void BoldDates(DateBoldEventArgs e) { int months = e.Size; e.DaysToBold = new int[months]; SelectionRange range = GetDisplayRange(false); int startMonth = range.Start.Month; int startYear = range.Start.Year; int numDates = arrayOfDates.Count; for (int i=0; i = 0 && DateTime.Compare(date, range.End) <= 0) { int month = date.Month; int year = date.Year; int index = (year == startYear) ? month - startMonth : month + year*MONTHS_IN_YEAR - startYear*MONTHS_IN_YEAR - startMonth; e.DaysToBold[index] |= (0x00000001<<(date.Day-1)); } } //now we figure out which monthly and annual dates to bold --startMonth; for (int i=0; i /// /// Compares only the day and month of each time. /// ///private bool CompareDayAndMonth(DateTime t1, DateTime t2) { return(t1.Day == t2.Day && t1.Month == t2.Month); } /// /// /// ///protected override void CreateHandle() { if (!RecreatingHandle) { IntPtr userCookie = UnsafeNativeMethods.ThemingScope.Activate(); try { NativeMethods.INITCOMMONCONTROLSEX icc = new NativeMethods.INITCOMMONCONTROLSEX(); icc.dwICC = NativeMethods.ICC_DATE_CLASSES; SafeNativeMethods.InitCommonControlsEx(icc); } finally { UnsafeNativeMethods.ThemingScope.Deactivate(userCookie); } } base.CreateHandle(); } /// /// /// Called to cleanup a MonthCalendar. Normally you do not need /// to call this as the garbage collector will cleanup the buffer /// for you. However, there may be times when you may want to expedite /// the garbage collectors cleanup. /// protected override void Dispose(bool disposing) { if (mdsBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(mdsBuffer); mdsBuffer = IntPtr.Zero; } base.Dispose(disposing); } // Return a localized string representation of the given DateTime value. // Used for throwing exceptions, etc. // private static string FormatDate(DateTime value) { return value.ToString("d", CultureInfo.CurrentCulture); } ////// /// Retrieves date information that represents the low and high limits of the /// control's display. /// public SelectionRange GetDisplayRange(bool visible) { if (visible) return GetMonthRange(NativeMethods.GMR_VISIBLE); else return GetMonthRange(NativeMethods.GMR_DAYSTATE); } ////// /// Retrieves the enumeration value corresponding to the hit area. /// ///private HitArea GetHitArea(int hit) { switch (hit) { case NativeMethods.MCHT_TITLEBK: return HitArea.TitleBackground; case NativeMethods.MCHT_TITLEMONTH: return HitArea.TitleMonth; case NativeMethods.MCHT_TITLEYEAR: return HitArea.TitleYear; case NativeMethods.MCHT_TITLEBTNNEXT: return HitArea.NextMonthButton; case NativeMethods.MCHT_TITLEBTNPREV: return HitArea.PrevMonthButton; case NativeMethods.MCHT_CALENDARBK: return HitArea.CalendarBackground; case NativeMethods.MCHT_CALENDARDATE: return HitArea.Date; case NativeMethods.MCHT_CALENDARDATENEXT: return HitArea.NextMonthDate; case NativeMethods.MCHT_CALENDARDATEPREV: return HitArea.PrevMonthDate; case NativeMethods.MCHT_CALENDARDAY: return HitArea.DayOfWeek; case NativeMethods.MCHT_CALENDARWEEKNUM: return HitArea.WeekNumbers; case NativeMethods.MCHT_TODAYLINK: return HitArea.TodayLink; default: return HitArea.Nowhere; } } /// /// /// stub for getMinReqRect (int, boolean) /// ///private Size GetMinReqRect() { return GetMinReqRect(0, false, false); } /// /// /// Used internally to get the minimum size needed to display the /// MonthCalendar. This is needed because /// NativeMethods.MCM_GETMINREQRECT returns an incorrect value if showToday /// is set to false. If updateRows is true, then the /// number of rows will be updated according to height. /// ///private Size GetMinReqRect(int newDimensionLength, bool updateRows, bool updateCols) { Size minSize = SingleMonthSize; // Calculate calendar height // Size textExtent; using (WindowsFont font = WindowsFont.FromFont(this.Font)) { // this is the string that Windows uses to determine the extent of the today string textExtent = WindowsGraphicsCacheManager.MeasurementGraphics.GetTextExtent(DateTime.Now.ToShortDateString(), font); } int todayHeight = textExtent.Height + 4; // The constant 4 is from the comctl32 MonthCalendar source code int calendarHeight = minSize.Height; if (ShowToday) { // If ShowToday is true, then minSize already includes the height of the today string. // So we remove it to get the actual calendar height. // calendarHeight -= todayHeight; } if (updateRows) { Debug.Assert(calendarHeight > INSERT_HEIGHT_SIZE, "Divide by 0"); int nRows = (newDimensionLength - todayHeight + INSERT_HEIGHT_SIZE)/(calendarHeight + INSERT_HEIGHT_SIZE); this.dimensions.Height = (nRows < 1) ? 1 : nRows; } if (updateCols) { Debug.Assert(minSize.Width > INSERT_WIDTH_SIZE, "Divide by 0"); int nCols = (newDimensionLength - ExtraPadding)/minSize.Width; this.dimensions.Width = (nCols < 1) ? 1 : nCols; } minSize.Width = (minSize.Width + INSERT_WIDTH_SIZE) * dimensions.Width - INSERT_WIDTH_SIZE; minSize.Height = (calendarHeight + INSERT_HEIGHT_SIZE) * dimensions.Height - INSERT_HEIGHT_SIZE + todayHeight; // If the width we've calculated is too small to fit the Today string, enlarge the width to fit // if (IsHandleCreated) { int maxTodayWidth = (int)SendMessage(NativeMethods.MCM_GETMAXTODAYWIDTH, 0, 0); if (maxTodayWidth > minSize.Width) { minSize.Width = maxTodayWidth; } } // Fudge factor // minSize.Width += ExtraPadding; minSize.Height += ExtraPadding; return minSize; } /// /// /// ///private SelectionRange GetMonthRange(int flag) { NativeMethods.SYSTEMTIMEARRAY sa = new NativeMethods.SYSTEMTIMEARRAY(); SelectionRange range = new SelectionRange(); UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_GETMONTHRANGE, flag, sa); NativeMethods.SYSTEMTIME st = new NativeMethods.SYSTEMTIME(); st.wYear = sa.wYear1; st.wMonth = sa.wMonth1; st.wDayOfWeek = sa.wDayOfWeek1; st.wDay = sa.wDay1; range.Start = DateTimePicker.SysTimeToDateTime(st); st.wYear = sa.wYear2; st.wMonth = sa.wMonth2; st.wDayOfWeek = sa.wDayOfWeek2; st.wDay = sa.wDay2; range.End = DateTimePicker.SysTimeToDateTime(st); return range; } /// /// /// Called by setBoundsCore. If updateRows is true, then the /// number of rows will be updated according to height. /// ///private int GetPreferredHeight(int height, bool updateRows) { Size preferredSize = GetMinReqRect(height, updateRows, false); return preferredSize.Height; } /// /// /// Called by setBoundsCore. If updateCols is true, then the /// number of columns will be updated according to width. /// ///private int GetPreferredWidth(int width, bool updateCols) { Size preferredSize = GetMinReqRect(width, false, updateCols); return preferredSize.Width; } /// /// /// Determines which portion of a month calendar control is at /// at a given point on the screen. /// public HitTestInfo HitTest(int x, int y) { NativeMethods.MCHITTESTINFO mchi = new NativeMethods.MCHITTESTINFO(); mchi.pt_x = x; mchi.pt_y = y; mchi.cbSize = Marshal.SizeOf(typeof(NativeMethods.MCHITTESTINFO)); UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_HITTEST, 0, mchi); // If the hit area has an associated valid date, get it // HitArea hitArea = GetHitArea(mchi.uHit); if (HitTestInfo.HitAreaHasValidDateTime(hitArea)) { NativeMethods.SYSTEMTIME sys = new NativeMethods.SYSTEMTIME(); sys.wYear = mchi.st_wYear; sys.wMonth = mchi.st_wMonth; sys.wDayOfWeek = mchi.st_wDayOfWeek; sys.wDay = mchi.st_wDay; sys.wHour = mchi.st_wHour; sys.wMinute = mchi.st_wMinute; sys.wSecond = mchi.st_wSecond; sys.wMilliseconds = mchi.st_wMilliseconds; return new HitTestInfo(new Point(mchi.pt_x, mchi.pt_y), hitArea, DateTimePicker.SysTimeToDateTime(sys)); } else { return new HitTestInfo(new Point(mchi.pt_x, mchi.pt_y), hitArea); } } ////// /// Determines which portion of a month calendar control is at /// at a given point on the screen. /// public HitTestInfo HitTest(Point point) { return HitTest(point.X, point.Y); } ////// /// Handling special input keys, such as pgup, pgdown, home, end, etc... /// protected override bool IsInputKey(Keys keyData) { if ((keyData & Keys.Alt) == Keys.Alt) return false; switch (keyData & Keys.KeyCode) { case Keys.PageUp: case Keys.PageDown: case Keys.Home: case Keys.End: return true; } return base.IsInputKey(keyData); } ////// /// Overrides Control.OnHandleCreated() /// ///protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); SetSelRange(selectionStart, selectionEnd); if (maxSelectionCount != DEFAULT_MAX_SELECTION_COUNT) { SendMessage(NativeMethods.MCM_SETMAXSELCOUNT, maxSelectionCount, 0); } AdjustSize(); if (todayDateSet) { NativeMethods.SYSTEMTIME st = DateTimePicker.DateTimeToSysTime(todayDate); UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETTODAY, 0, st); } SetControlColor(NativeMethods.MCSC_TEXT, ForeColor); SetControlColor(NativeMethods.MCSC_MONTHBK, BackColor); SetControlColor(NativeMethods.MCSC_TITLEBK, titleBackColor); SetControlColor(NativeMethods.MCSC_TITLETEXT, titleForeColor); SetControlColor(NativeMethods.MCSC_TRAILINGTEXT, trailingForeColor); int firstDay; if (firstDayOfWeek == Day.Default) { firstDay = NativeMethods.LOCALE_IFIRSTDAYOFWEEK; } else { firstDay = (int)firstDayOfWeek; } SendMessage(NativeMethods.MCM_SETFIRSTDAYOFWEEK, 0, firstDay); SetRange(); if (scrollChange != DEFAULT_SCROLL_CHANGE) { SendMessage(NativeMethods.MCM_SETMONTHDELTA, scrollChange, 0); } SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.MarshaledUserPreferenceChanged); } /// /// /// Overrides Control.OnHandleDestroyed() /// ///protected override void OnHandleDestroyed(EventArgs e) { SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.MarshaledUserPreferenceChanged); base.OnHandleDestroyed(e); } /// /// /// Fires the event indicating that the currently selected date /// or range of dates has changed. /// protected virtual void OnDateChanged(DateRangeEventArgs drevent) { if (onDateChanged != null) { onDateChanged(this, drevent); } } ////// /// Fires the event indicating that the user has changed his\her selection. /// protected virtual void OnDateSelected(DateRangeEventArgs drevent) { if (onDateSelected != null) { onDateSelected(this, drevent); } } ////// /// protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); AdjustSize(); } ///[To be supplied.] ////// /// protected override void OnForeColorChanged(EventArgs e) { base.OnForeColorChanged(e); SetControlColor(NativeMethods.MCSC_TEXT, ForeColor); } ///[To be supplied.] ////// /// protected override void OnBackColorChanged(EventArgs e) { base.OnBackColorChanged(e); SetControlColor(NativeMethods.MCSC_MONTHBK, BackColor); } ///[To be supplied.] ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void OnRightToLeftLayoutChanged(EventArgs e) { if (GetAnyDisposingInHierarchy()) { return; } if (RightToLeft == RightToLeft.Yes) { RecreateHandle(); } if (onRightToLeftLayoutChanged != null) { onRightToLeftLayoutChanged(this, e); } } ///[To be supplied.] ////// /// Removes all annually bolded days. Be sure to call updateBoldedDates() afterwards. /// public void RemoveAllAnnuallyBoldedDates() { this.annualArrayOfDates.Clear(); for (int i=0; i/// /// Removes all the bolded days. Be sure to call updateBoldedDates() afterwards. /// public void RemoveAllBoldedDates() { this.arrayOfDates.Clear(); } ////// /// Removes all monthly bolded days. Be sure to call updateBoldedDates() afterwards. /// public void RemoveAllMonthlyBoldedDates() { this.monthlyArrayOfDates.Clear(); datesToBoldMonthly = 0; } ////// /// Removes an annually bolded date. If the date is not found in the /// bolded date list, then no action is taken. If date occurs more than /// once in the bolded date list, then only the first date is removed. When /// comparing dates, only the day and month are used. Be sure to call /// updateBoldedDates afterwards. /// public void RemoveAnnuallyBoldedDate(DateTime date) { int length = annualArrayOfDates.Count; int i=0; for (; i/// /// Removes a bolded date. If the date is not found in the /// bolded date list, then no action is taken. If date occurs more than /// once in the bolded date list, then only the first date is removed. /// Be sure to call updateBoldedDates() afterwards. /// public void RemoveBoldedDate(DateTime date) { int length = arrayOfDates.Count; for (int i=0; i/// /// Removes a monthly bolded date. If the date is not found in the /// bolded date list, then no action is taken. If date occurs more than /// once in the bolded date list, then only the first date is removed. When /// comparing dates, only the day and month are used. Be sure to call /// updateBoldedDates afterwards. /// public void RemoveMonthlyBoldedDate(DateTime date) { int length = monthlyArrayOfDates.Count; int i=0; for (; i/// /// Resets the maximum selectable date. By default value, there is no /// upper limit. /// private void ResetMaxDate() { MaxDate = DateTime.MaxValue; } ////// /// Resets the minimum selectable date. By default value, there is no /// lower limit. /// private void ResetMinDate() { MinDate = DateTime.MinValue; } private void ResetMonthlyBoldedDates() { monthlyArrayOfDates.Clear(); } ////// /// Resets the limits of the selection range. By default value, the upper /// and lower limit is the current date. /// private void ResetSelectionRange() { SetSelectionRange(Now, Now); } private void ResetTrailingForeColor() { TrailingForeColor = DEFAULT_TRAILING_FORE_COLOR; } private void ResetTitleForeColor() { TitleForeColor = DEFAULT_TITLE_FORE_COLOR; } private void ResetTitleBackColor() { TitleBackColor = DEFAULT_TITLE_BACK_COLOR; } ////// /// Resets the "today"'s date. By default value, "today" is the /// current date (and is automatically updated when the clock crosses /// over to the next day). /// If you set the today date yourself (using the TodayDate property) /// the control will no longer automatically update the current day /// for you. To re-enable this behavior, ResetTodayDate() is used. /// private void ResetTodayDate() { todayDateSet = false; UpdateTodayDate(); } ////// /// reqSize = # elements in int[] array /// /// The size argument should be greater than 0. /// Because of the nature of MonthCalendar, we can expect that /// the requested size will not be ridiculously large, hence /// it is not necessary to decrease the size of an allocated /// block if the new requested size is smaller. /// ///private IntPtr RequestBuffer(int reqSize) { Debug.Assert(reqSize > 0, "Requesting a ridiculously small buffer"); int intSize = 4; // if the current buffer size is insufficient... if (reqSize * intSize > mdsBufferSize) { // free and expand the buffer, if (mdsBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(mdsBuffer); mdsBuffer = IntPtr.Zero; } // Round up to the nearest multiple of MINIMUM_ALLOC_SIZE float quotient = (float) (reqSize-1) / MINIMUM_ALLOC_SIZE; int actualSize = ((int) (quotient+1)) * MINIMUM_ALLOC_SIZE; Debug.Assert(actualSize >= reqSize, "Tried to round up, but got it wrong"); mdsBufferSize = actualSize * intSize; mdsBuffer = Marshal.AllocHGlobal(mdsBufferSize); return mdsBuffer; } return mdsBuffer; } /// /// /// Overrides Control.SetBoundsCore to enforce auto-sizing. /// ///protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { Rectangle oldBounds = Bounds; Size max = SystemInformation.MaxWindowTrackSize; if (width != oldBounds.Width) { if (width > max.Width) width = max.Width; width = GetPreferredWidth(width, true); } if (height != oldBounds.Height) { if (height > max.Height) height = max.Height; height = GetPreferredHeight(height, true); } base.SetBoundsCore(x, y, width, height, specified); } /// /// /// If the handle has been created, this applies the color to the control /// ///private void SetControlColor(int colorIndex, Color value) { if (IsHandleCreated) { SendMessage(NativeMethods.MCM_SETCOLOR, colorIndex, ColorTranslator.ToWin32(value)); } } /// /// /// Updates the window handle with the min/max ranges if it has been /// created. /// ///private void SetRange() { SetRange(DateTimePicker.EffectiveMinDate(minDate), DateTimePicker.EffectiveMaxDate(maxDate)); } private void SetRange(DateTime minDate, DateTime maxDate) { // Keep selection range within passed in minDate and maxDate if (selectionStart < minDate) { selectionStart = minDate; } if (selectionStart > maxDate) { selectionStart = maxDate; } if (selectionEnd < minDate) { selectionEnd = minDate; } if (selectionEnd > maxDate) { selectionEnd = maxDate; } SetSelRange(selectionStart, selectionEnd); // Updated the calendar range // if (IsHandleCreated) { int flag = 0; NativeMethods.SYSTEMTIMEARRAY sa = new NativeMethods.SYSTEMTIMEARRAY(); flag |= NativeMethods.GDTR_MIN | NativeMethods.GDTR_MAX; NativeMethods.SYSTEMTIME sys = DateTimePicker.DateTimeToSysTime(minDate); sa.wYear1 = sys.wYear; sa.wMonth1 = sys.wMonth; sa.wDayOfWeek1 = sys.wDayOfWeek; sa.wDay1 = sys.wDay; sys = DateTimePicker.DateTimeToSysTime(maxDate); sa.wYear2 = sys.wYear; sa.wMonth2 = sys.wMonth; sa.wDayOfWeek2 = sys.wDayOfWeek; sa.wDay2 = sys.wDay; if ((int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETRANGE, flag, sa) == 0) throw new InvalidOperationException(SR.GetString(SR.MonthCalendarRange, minDate.ToShortDateString(), maxDate.ToShortDateString())); } } /// /// /// Sets the number of columns and rows to display. /// public void SetCalendarDimensions(int x, int y) { if (x < 1) { throw new ArgumentOutOfRangeException("x", SR.GetString(SR.MonthCalendarInvalidDimensions, (x).ToString("D", CultureInfo.CurrentCulture), (y).ToString("D", CultureInfo.CurrentCulture))); } if (y < 1) { throw new ArgumentOutOfRangeException("y", SR.GetString(SR.MonthCalendarInvalidDimensions, (x).ToString("D", CultureInfo.CurrentCulture), (y).ToString("D", CultureInfo.CurrentCulture))); } // MonthCalendar limits the dimensions to x * y <= 12 // i.e. a maximum of twelve months can be displayed at a time // The following code emulates what is done inside monthcalendar (in comctl32.dll): // The dimensions are gradually reduced until the inequality above holds. // while (x * y > 12) { if (x > y) { x--; } else { y--; } } if (dimensions.Width != x || dimensions.Height != y) { this.dimensions.Width = x; this.dimensions.Height = y; AdjustSize(); } } ////// /// Sets date as the current selected date. The start and begin of /// the selection range will both be equal to date. /// public void SetDate(DateTime date) { if (date.Ticks < minDate.Ticks) { throw new ArgumentOutOfRangeException("date", SR.GetString(SR.InvalidLowBoundArgumentEx, "date", FormatDate(date), "MinDate")); } if (date.Ticks > maxDate.Ticks) { throw new ArgumentOutOfRangeException("date", SR.GetString(SR.InvalidHighBoundArgumentEx, "date", FormatDate(date), "MaxDate")); } SetSelectionRange(date, date); } ////// /// Sets the selection for a month calendar control to a given date range. /// The selection range will not be set if the selection range exceeds the /// maximum selection count. /// public void SetSelectionRange(DateTime date1, DateTime date2) { // Keep the dates within the min and max dates if (date1.Ticks < minDate.Ticks) { throw new ArgumentOutOfRangeException("date1", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionStart", FormatDate(date1), "MinDate")); } if (date1.Ticks > maxDate.Ticks) { throw new ArgumentOutOfRangeException("date1", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionEnd", FormatDate(date1), "MaxDate")); } if (date2.Ticks < minDate.Ticks) { throw new ArgumentOutOfRangeException("date2", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionStart", FormatDate(date2), "MinDate")); } if (date2.Ticks > maxDate.Ticks) { throw new ArgumentOutOfRangeException("date2", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionEnd", FormatDate(date2), "MaxDate")); } // If date1 > date2, we just select date2 (compat) // if (date1 > date2) { date2 = date1; } // If the range exceeds maxSelectionCount, compare with the previous range and adjust whichever // limit hasn't changed. // if ((date2 - date1).Days >= maxSelectionCount) { if (date1.Ticks == selectionStart.Ticks) { // Bring start date forward // date1 = date2.AddDays(1 - maxSelectionCount); } else { // Bring end date back // date2 = date1.AddDays(maxSelectionCount - 1); } } // Set the range SetSelRange(date1, date2); } ////// /// Upper must be greater than Lower /// ///private void SetSelRange(DateTime lower, DateTime upper) { Debug.Assert(lower.Ticks <= upper.Ticks, "lower must be less than upper"); bool changed = false; if (selectionStart != lower || selectionEnd != upper) { changed = true; selectionStart = lower; selectionEnd = upper; } // always set the value on the control, to ensure that // it is up to date. // if (IsHandleCreated) { NativeMethods.SYSTEMTIMEARRAY sa = new NativeMethods.SYSTEMTIMEARRAY(); NativeMethods.SYSTEMTIME sys = DateTimePicker.DateTimeToSysTime(lower); sa.wYear1 = sys.wYear; sa.wMonth1 = sys.wMonth; sa.wDayOfWeek1 = sys.wDayOfWeek; sa.wDay1 = sys.wDay; sys = DateTimePicker.DateTimeToSysTime(upper); sa.wYear2 = sys.wYear; sa.wMonth2 = sys.wMonth; sa.wDayOfWeek2 = sys.wDayOfWeek; sa.wDay2 = sys.wDay; UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETSELRANGE , 0, sa); } if (changed) { OnDateChanged(new DateRangeEventArgs(lower, upper)); } } private bool ShouldSerializeAnnuallyBoldedDates() { return annualArrayOfDates.Count > 0; } private bool ShouldSerializeBoldedDates() { return arrayOfDates.Count > 0; } private bool ShouldSerializeCalendarDimensions() { return !dimensions.Equals(new Size(1, 1)); } private bool ShouldSerializeTrailingForeColor() { return !TrailingForeColor.Equals(DEFAULT_TRAILING_FORE_COLOR); } private bool ShouldSerializeTitleForeColor() { return !TitleForeColor.Equals(DEFAULT_TITLE_FORE_COLOR); } private bool ShouldSerializeTitleBackColor() { return !TitleBackColor.Equals(DEFAULT_TITLE_BACK_COLOR); } private bool ShouldSerializeMonthlyBoldedDates() { return monthlyArrayOfDates.Count > 0; } /// /// /// Retrieves true if the maxDate should be persisted in code gen. /// private bool ShouldSerializeMaxDate() { return maxDate != DateTimePicker.MaximumDateTime && maxDate != DateTime.MaxValue; } ////// /// Retrieves true if the minDate should be persisted in code gen. /// private bool ShouldSerializeMinDate() { return minDate != DateTimePicker.MinimumDateTime && minDate != DateTime.MinValue; } ////// /// Retrieves true if the selectionRange should be persisted in code gen. /// private bool ShouldSerializeSelectionRange() { return !DateTime.Equals(selectionEnd, selectionStart); } ////// /// Retrieves true if the todayDate should be persisted in code gen. /// private bool ShouldSerializeTodayDate() { return todayDateSet; } ////// /// Returns a string representation for this control. /// ///public override string ToString() { string s = base.ToString(); return s + ", " + SelectionRange.ToString(); } /// /// /// Forces month calendar to display the current set of bolded dates. /// public void UpdateBoldedDates() { RecreateHandle(); } ////// /// Updates the current setting for "TODAY" in the MonthCalendar control /// If the today date is set, the control will be set to that. Otherwise, /// it will be set to null (running clock mode - the today date will be /// automatically updated). /// private void UpdateTodayDate() { if (IsHandleCreated) { NativeMethods.SYSTEMTIME st = null; if (todayDateSet) { st = DateTimePicker.DateTimeToSysTime(todayDate); } UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETTODAY, 0, st); } } private void MarshaledUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs pref) { try { //use begininvoke instead of invoke in case the destination thread is not processing messages. BeginInvoke(new UserPreferenceChangedEventHandler(this.UserPreferenceChanged), new object[] { sender, pref }); } catch (InvalidOperationException) { } //if the destination thread does not exist, don't send. } private void UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs pref) { if (pref.Category == UserPreferenceCategory.Locale) { // We need to recreate the monthcalendar handle when the locale changes, because // the day names etc. are only updated on a handle recreate (comctl32 limitation). // RecreateHandle(); } } ////// /// Handles the MCN_SELCHANGE notification /// ///private void WmDateChanged(ref Message m) { NativeMethods.NMSELCHANGE nmmcsc = (NativeMethods.NMSELCHANGE)m.GetLParam(typeof(NativeMethods.NMSELCHANGE)); DateTime start = selectionStart = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelStart); DateTime end = selectionEnd = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelEnd); //subhag if (start.Ticks < minDate.Ticks || end.Ticks < minDate.Ticks) SetSelRange(minDate,minDate); else if (start.Ticks > maxDate.Ticks || end.Ticks > maxDate.Ticks) SetSelRange(maxDate,maxDate); //end subhag OnDateChanged(new DateRangeEventArgs(start, end)); } /// /// /// Handles the MCN_GETDAYSTATE notification /// ///private void WmDateBold(ref Message m) { NativeMethods.NMDAYSTATE nmmcds = (NativeMethods.NMDAYSTATE)m.GetLParam(typeof(NativeMethods.NMDAYSTATE)); DateTime start = DateTimePicker.SysTimeToDateTime(nmmcds.stStart); DateBoldEventArgs boldEvent = new DateBoldEventArgs(start, nmmcds.cDayState); BoldDates(boldEvent); mdsBuffer = RequestBuffer(boldEvent.Size); // copy boldEvent into mdsBuffer Marshal.Copy(boldEvent.DaysToBold, 0, mdsBuffer, boldEvent.Size); // now we replug DateBoldEventArgs info into NMDAYSTATE nmmcds.prgDayState = mdsBuffer; Marshal.StructureToPtr(nmmcds, m.LParam, false); } /// /// /// Handles the MCN_SELECT notification /// ///private void WmDateSelected(ref Message m) { NativeMethods.NMSELCHANGE nmmcsc = (NativeMethods.NMSELCHANGE)m.GetLParam(typeof(NativeMethods.NMSELCHANGE)); DateTime start = selectionStart = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelStart); DateTime end = selectionEnd = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelEnd); //subhag if (start.Ticks < minDate.Ticks || end.Ticks < minDate.Ticks) SetSelRange(minDate,minDate); else if (start.Ticks > maxDate.Ticks || end.Ticks > maxDate.Ticks) SetSelRange(maxDate,maxDate); //end subhag OnDateSelected(new DateRangeEventArgs(start, end)); } /// /// /// Handles the WM_GETDLGCODE message /// ///private void WmGetDlgCode(ref Message m) { // The MonthCalendar does its own handling of arrow keys m.Result = (IntPtr)NativeMethods.DLGC_WANTARROWS; } /// /// /// Handles the WM_COMMAND messages reflected from the parent control. /// ///private void WmReflectCommand(ref Message m) { if (m.HWnd == Handle) { NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR)); switch (nmhdr.code) { case NativeMethods.MCN_SELECT: WmDateSelected(ref m); break; case NativeMethods.MCN_SELCHANGE: WmDateChanged(ref m); break; case NativeMethods.MCN_GETDAYSTATE: WmDateBold(ref m); break; } } } /// /// /// Overrided wndProc /// ///[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_LBUTTONDOWN: FocusInternal(); if (!ValidationCancelled) { base.WndProc(ref m); } break; case NativeMethods.WM_GETDLGCODE: WmGetDlgCode(ref m); break; case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY: WmReflectCommand(ref m); base.WndProc(ref m); break; default: base.WndProc(ref m); break; } } /// /// /// HitTestInfo objects are returned by MonthCalendar in response to the hitTest method. /// HitTestInfo is for informational purposes only; the user should not construct these objects, and /// cannot modify any of the members. /// public sealed class HitTestInfo { readonly Point point; readonly HitArea hitArea; readonly DateTime time; ////// /// ///internal HitTestInfo(Point pt, HitArea area, DateTime time) { this.point = pt; this.hitArea = area; this.time = time; } /// /// /// This constructor is used when the DateTime member is invalid. /// ///internal HitTestInfo(Point pt, HitArea area) { this.point = pt; this.hitArea = area; } /// /// /// The point that was hit-tested /// public Point Point { get { return point; } } ////// /// Output member that receives an enumeration value from System.Windows.Forms.MonthCalendar.HitArea /// representing the result of the hit-test operation. /// public HitArea HitArea { get { return hitArea; } } ////// /// The time information specific to the location that was hit-tested. This value /// will only be valid at certain values of hitArea. /// public DateTime Time { get { return time; } } ////// /// Determines whether a given HitArea should have a corresponding valid DateTime /// ///internal static bool HitAreaHasValidDateTime(HitArea hitArea) { switch (hitArea) { case HitArea.Date: //case HitArea.DayOfWeek: comCtl does not provide a valid date case HitArea.WeekNumbers: return true; } return false; } } /// /// /// This enumeration has specific areas of the MonthCalendar control as its enumerated values. /// The hitArea member of System.Windows.Forms.Win32.HitTestInfo will be one of these enumerated values, and /// indicates which portion of a month calendar is under a specific point. /// public enum HitArea { ////// /// The given point was not on the month calendar control, or it was in an inactive portion of the control. /// Nowhere = 0, ////// /// The given point was over the background of a month's title /// TitleBackground = 1, ////// /// The given point was in a month's title bar, over a month name /// TitleMonth = 2, ////// /// The given point was in a month's title bar, over the year value /// TitleYear = 3, ////// /// The given point was over the button at the top right corner of the control. /// If the user clicks here, the month calendar will scroll its display to the next /// month or set of months /// NextMonthButton = 4, ////// /// The given point was over the button at the top left corner of the control. If the /// user clicks here, the month calendar will scroll its display to the previous month /// or set of months /// PrevMonthButton = 5, ////// /// The given point was in the calendar's background /// CalendarBackground = 6, ////// /// The given point was on a particular date within the calendar, and the time member of /// HitTestInfo will be set to the date at the given point. /// Date = 7, ////// /// The given point was over a date from the next month (partially displayed at the end of /// the currently displayed month). If the user clicks here, the month calendar will scroll /// its display to the next month or set of months. /// NextMonthDate = 8, ////// /// The given point was over a date from the previous month (partially displayed at the end /// of the currently displayed month). If the user clicks here, the month calendar will scroll /// its display to the previous month or set of months. /// PrevMonthDate = 9, ////// /// The given point was over a day abbreviation ("Fri", for example). The time member /// of HitTestInfo will be set to the corresponding date on the top row. /// DayOfWeek = 10, ////// /// The given point was over a week number. This will only occur if the showWeekNumbers /// property of MonthCalendar is enabled. The time member of HitTestInfo will be set to /// the corresponding date in the leftmost column. /// WeekNumbers = 11, ////// /// The given point was on the "today" link at the bottom of the month calendar control /// TodayLink = 12, } } // end class MonthCalendar } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* */ namespace System.Windows.Forms { using System.Runtime.Serialization.Formatters; using System.Runtime.Remoting; using System.Runtime.InteropServices; using System.Diagnostics; using System; using System.Security.Permissions; using System.Globalization; using System.Windows.Forms.Internal; using System.ComponentModel; using System.ComponentModel.Design; using ArrayList = System.Collections.ArrayList; using System.Drawing; using Microsoft.Win32; using System.Windows.Forms.Layout; ////// /// This control is an encapsulateion of the Windows month calendar control. /// A month calendar control implements a calendar-like user interface, that /// provides the user with a very intuitive and recognizable method of entering /// or selecting a date. /// Users can also select which days bold. The most efficient way to add the /// bolded dates is via an array all at once. (The below descriptions can be applied /// equally to annually and monthly bolded dates as well) /// The following is an example of this: /// [ ComVisible(true), ClassInterface(ClassInterfaceType.AutoDispatch), DefaultProperty("SelectionRange"), DefaultEvent("DateChanged"), DefaultBindingProperty("SelectionRange"), Designer("System.Windows.Forms.Design.MonthCalendarDesigner, " + AssemblyRef.SystemDesign), SRDescription(SR.DescriptionMonthCalendar) ] public class MonthCalendar : Control { const long DAYS_TO_1601 = 548229; const long DAYS_TO_10000 = 3615900; static readonly Color DEFAULT_TITLE_BACK_COLOR = SystemColors.ActiveCaption; static readonly Color DEFAULT_TITLE_FORE_COLOR = SystemColors.ActiveCaptionText; static readonly Color DEFAULT_TRAILING_FORE_COLOR = SystemColors.GrayText; private const int MINIMUM_ALLOC_SIZE = 12; // minimum size to expand the buffer by private const int MONTHS_IN_YEAR = 12; ////// MonthCalendar mc = new MonthCalendar(); /// // add specific dates to bold /// DateTime[] time = new DateTime[3]; /// time[0] = DateTime.Now; /// time[1] = time[0].addDays(2); /// time[2] = time[1].addDays(2); /// mc.setBoldedDates(time); ///
/// Removal of all bolded dates is accomplished with: ////// mc.removeAllBoldedDates(); ///
/// Although less efficient, the user may need to add or remove bolded dates one at /// a time. To improve the performance of this, neither addBoldedDate nor /// removeBoldedDate repaints the monthcalendar. The user must call updateBoldedDates /// to force the repaint of the bolded dates, otherwise the monthCalendar will not /// paint properly. /// The following is an example of this: ////// DateTime time1 = new DateTime("3/5/98"); /// DateTime time2 = new DateTime("4/19/98"); /// mc.addBoldedDate(time1); /// mc.addBoldedDate(time2); /// mc.removeBoldedDate(time1); /// mc.updateBoldedDates(); ///
/// The same applies to addition and removal of annual and monthly bolded dates. ////// /// This is the arbitrary number of pixels that the Win32 control /// inserts between calendars horizontally, regardless of font. /// ///private const int INSERT_WIDTH_SIZE = 6; /// /// /// This is the arbitrary number of pixels that the Win32 control /// inserts between calendars vertically, regardless of font. /// ///private const int INSERT_HEIGHT_SIZE = 6; // From comctl32 MonthCalendar sources CALBORDER private const Day DEFAULT_FIRST_DAY_OF_WEEK = Day.Default; private const int DEFAULT_MAX_SELECTION_COUNT = 7; private const int DEFAULT_SCROLL_CHANGE = 0; private const int UNIQUE_DATE = 0; private const int ANNUAL_DATE = 1; private const int MONTHLY_DATE = 2; private static readonly Size DefaultSingleMonthSize = new Size(176, 153); private const int MaxScrollChange = 20000; private const int ExtraPadding = 2; private IntPtr mdsBuffer = IntPtr.Zero; private int mdsBufferSize = 0; // styles private Color titleBackColor = DEFAULT_TITLE_BACK_COLOR; private Color titleForeColor = DEFAULT_TITLE_FORE_COLOR; private Color trailingForeColor = DEFAULT_TRAILING_FORE_COLOR; private bool showToday = true; private bool showTodayCircle = true; private bool showWeekNumbers = false; private bool rightToLeftLayout = false; // properties private Size dimensions = new Size(1, 1); private int maxSelectionCount = DEFAULT_MAX_SELECTION_COUNT; // VSWhidbey 400284: Reconcile out-of-range min/max values in the property getters. private DateTime maxDate = DateTime.MaxValue; private DateTime minDate = DateTime.MinValue; private int scrollChange = DEFAULT_SCROLL_CHANGE; private bool todayDateSet = false; // Has TodayDate been explicitly set? private DateTime todayDate = DateTime.Now.Date; private DateTime selectionStart; private DateTime selectionEnd; private Day firstDayOfWeek = DEFAULT_FIRST_DAY_OF_WEEK; /// /// /// Bitmask for the annually bolded dates. Months start on January. /// ///private int[] monthsOfYear = new int[12]; /// /// /// Bitmask for the dates bolded monthly. /// ///private int datesToBoldMonthly = 0; /// /// /// Lists are slow, so this section can be optimized. /// Implementation is such that inserts are fast, removals are slow. /// ///private ArrayList arrayOfDates = new ArrayList(); private ArrayList annualArrayOfDates = new ArrayList(); // we have to maintain these lists too. private ArrayList monthlyArrayOfDates = new ArrayList(); // notifications private DateRangeEventHandler onDateChanged; private DateRangeEventHandler onDateSelected; private EventHandler onRightToLeftLayoutChanged; /// /// /// Creates a new MonthCalendar object. Styles are the default for a /// regular month calendar control. /// public MonthCalendar() : base() { selectionStart = todayDate; selectionEnd = todayDate; SetStyle(ControlStyles.UserPaint, false); SetStyle(ControlStyles.StandardClick, false); TabStop = true; } ////// /// The array of DateTime objects that determines which annual days are shown /// in bold. /// [ Localizable(true), SRDescription(SR.MonthCalendarAnnuallyBoldedDatesDescr) ] public DateTime[] AnnuallyBoldedDates { get { DateTime[] dateTimes = new DateTime[annualArrayOfDates.Count]; for (int i=0;i < annualArrayOfDates.Count; ++i) { dateTimes[i] = (DateTime)this.annualArrayOfDates[i]; } return dateTimes; } set { // this.annualArrayOfDates.Clear(); for (int i=0; i0) { //add each boldeddate to our ArrayList... for (int i = 0; i < value.Length; i++) { this.annualArrayOfDates.Add(value[i]); } for (int i = 0; i < value.Length; ++i) { monthsOfYear[value[i].Month-1] |= 0x00000001<<(value[i].Day-1); } } RecreateHandle(); } } /// /// /// [SRDescription(SR.MonthCalendarMonthBackColorDescr)] public override Color BackColor { get { if (ShouldSerializeBackColor()) { return base.BackColor; } else { return SystemColors.Window; } } set { base.BackColor = value; } } ///[To be supplied.] ////// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override Image BackgroundImage { get { return base.BackgroundImage; } set { base.BackgroundImage = value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageChanged { add { base.BackgroundImageChanged += value; } remove { base.BackgroundImageChanged -= value; } } /// /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public override ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler BackgroundImageLayoutChanged { add { base.BackgroundImageLayoutChanged += value; } remove { base.BackgroundImageLayoutChanged -= value; } } /// /// /// The array of DateTime objects that determines which non-recurring /// specified dates are shown in bold. /// /*Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced),*/ [Localizable(true)] public DateTime[] BoldedDates { get { DateTime[] dateTimes = new DateTime[arrayOfDates.Count]; for (int i=0;i < arrayOfDates.Count; ++i) { dateTimes[i] = (DateTime)this.arrayOfDates[i]; } return dateTimes; } set { // this.arrayOfDates.Clear(); if (value != null && value.Length > 0) { //add each boldeddate to our ArrayList... for (int i = 0; i < value.Length; i++) { this.arrayOfDates.Add(value[i]); } } RecreateHandle(); } } ////// /// The number of columns and rows of months that will be displayed /// in the MonthCalendar control. /// [ SRCategory(SR.CatAppearance), Localizable(true), SRDescription(SR.MonthCalendarDimensionsDescr) ] public Size CalendarDimensions { get { return dimensions; } set { if (!this.dimensions.Equals(value)) SetCalendarDimensions(value.Width, value.Height); } } ////// /// This is called when creating a window. Inheriting classes can ovveride /// this to add extra functionality, but should not forget to first call /// base.getCreateParams() to make sure the control continues to work /// correctly. /// protected override CreateParams CreateParams { [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] get { CreateParams cp = base.CreateParams; cp.ClassName = NativeMethods.WC_MONTHCAL; cp.Style |= NativeMethods.MCS_MULTISELECT | NativeMethods.MCS_DAYSTATE; if (!showToday) cp.Style |= NativeMethods.MCS_NOTODAY; if (!showTodayCircle) cp.Style |= NativeMethods.MCS_NOTODAYCIRCLE; if (showWeekNumbers) cp.Style |= NativeMethods.MCS_WEEKNUMBERS; if (RightToLeft == RightToLeft.Yes && RightToLeftLayout == true) { //We want to turn on mirroring for Form explicitly. cp.ExStyle |= NativeMethods.WS_EX_LAYOUTRTL; //Don't need these styles when mirroring is turned on. cp.ExStyle &= ~(NativeMethods.WS_EX_RTLREADING | NativeMethods.WS_EX_RIGHT | NativeMethods.WS_EX_LEFTSCROLLBAR); } return cp; } } ///protected override ImeMode DefaultImeMode { get { return ImeMode.Disable; } } /// protected override Padding DefaultMargin { get { return new Padding(9); } } /// protected override Size DefaultSize { get { return GetMinReqRect(); } } /// /// /// This property is overridden and hidden from statement completion /// on controls that are based on Win32 Native Controls. /// [EditorBrowsable(EditorBrowsableState.Never)] protected override bool DoubleBuffered { get { return base.DoubleBuffered; } set { base.DoubleBuffered = value; } } ////// /// The first day of the week for the month calendar control. /// [ SRCategory(SR.CatBehavior), Localizable(true), DefaultValue(DEFAULT_FIRST_DAY_OF_WEEK), SRDescription(SR.MonthCalendarFirstDayOfWeekDescr) ] public Day FirstDayOfWeek { get { return firstDayOfWeek; } set { //valid values are 0x0 to 0x7 if (!ClientUtils.IsEnumValid(value, (int)value, (int)Day.Monday, (int)Day.Default)){ throw new InvalidEnumArgumentException("FirstDayOfWeek", (int)value, typeof(Day)); } if (value != firstDayOfWeek) { firstDayOfWeek = value; if (IsHandleCreated) { if (value == Day.Default) { RecreateHandle(); } else { SendMessage(NativeMethods.MCM_SETFIRSTDAYOFWEEK, 0, (int) value); } } } } } ////// /// [SRDescription(SR.MonthCalendarForeColorDescr)] public override Color ForeColor { get { if (ShouldSerializeForeColor()) { return base.ForeColor; } else { return SystemColors.WindowText; } } set { base.ForeColor = value; } } ///[To be supplied.] ///[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public ImeMode ImeMode { get { return base.ImeMode; } set { base.ImeMode = value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler ImeModeChanged { add { base.ImeModeChanged += value; } remove { base.ImeModeChanged -= value; } } /// /// /// The maximum allowable date that can be selected. By default, there /// is no maximum date. The maximum date is not set if max less than the /// current minimum date. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarMaxDateDescr) ] public DateTime MaxDate { get { return DateTimePicker.EffectiveMaxDate(maxDate); } set { if (value != maxDate) { if (value < DateTimePicker.EffectiveMinDate(minDate)) { throw new ArgumentOutOfRangeException("MaxDate", SR.GetString(SR.InvalidLowBoundArgumentEx, "MaxDate", FormatDate(value), "MinDate")); } maxDate = value; SetRange(); } } } ////// /// The maximum number of days that can be selected in a /// month calendar control. This method does not affect the current /// selection range. /// [ SRCategory(SR.CatBehavior), DefaultValue(DEFAULT_MAX_SELECTION_COUNT), SRDescription(SR.MonthCalendarMaxSelectionCountDescr) ] public int MaxSelectionCount { get { return maxSelectionCount; } set { if (value < 1) { throw new ArgumentOutOfRangeException("MaxSelectionCount", SR.GetString(SR.InvalidLowBoundArgumentEx, "MaxSelectionCount", (value).ToString("D", CultureInfo.CurrentCulture), (1).ToString(CultureInfo.CurrentCulture))); } if (value != maxSelectionCount) { if (IsHandleCreated) { if ((int)SendMessage(NativeMethods.MCM_SETMAXSELCOUNT, value, 0) == 0) throw new ArgumentException(SR.GetString(SR.MonthCalendarMaxSelCount, (value).ToString("D", CultureInfo.CurrentCulture)), "MaxSelectionCount"); } maxSelectionCount = value; } } } ////// /// The minimum allowable date that can be selected. By default, there /// is no minimum date. The minimum date is not set if min greater than the /// current maximum date. MonthCalendar does not support dates prior to 1753. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarMinDateDescr) ] public DateTime MinDate { get { return DateTimePicker.EffectiveMinDate(minDate); } set { if (value != minDate) { if (value > DateTimePicker.EffectiveMaxDate(maxDate)) { throw new ArgumentOutOfRangeException("MinDate", SR.GetString(SR.InvalidHighBoundArgument, "MinDate", FormatDate(value), "MaxDate")); } // If trying to set the minimum less than DateTimePicker.MinimumDateTime, throw // an exception. if (value < DateTimePicker.MinimumDateTime) { throw new ArgumentOutOfRangeException("MinDate", SR.GetString(SR.InvalidLowBoundArgumentEx, "MinDate", FormatDate(value), FormatDate(DateTimePicker.MinimumDateTime))); } minDate = value; SetRange(); } } } ////// /// The array of DateTime objects that determine which monthly days to bold. /// [ Localizable(true), SRDescription(SR.MonthCalendarMonthlyBoldedDatesDescr) ] public DateTime[] MonthlyBoldedDates { get { DateTime[] dateTimes = new DateTime[monthlyArrayOfDates.Count]; for (int i=0;i < monthlyArrayOfDates.Count; ++i) { dateTimes[i] = (DateTime)this.monthlyArrayOfDates[i]; } return dateTimes; } set { // this.monthlyArrayOfDates.Clear(); datesToBoldMonthly = 0; if (value != null && value.Length > 0) { //add each boldeddate to our ArrayList... for (int i = 0; i < value.Length; i++) { this.monthlyArrayOfDates.Add(value[i]); } for (int i = 0; i < value.Length; ++i) { datesToBoldMonthly |= 0x00000001<<(value[i].Day-1); } } RecreateHandle(); } } ////// /// ///private DateTime Now { get { return DateTime.Now.Date; } } /// /// /// [ Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public new Padding Padding { get { return base.Padding; } set { base.Padding = value;} } [ Browsable(false), EditorBrowsable(EditorBrowsableState.Never) ] public new event EventHandler PaddingChanged { add { base.PaddingChanged += value; } remove { base.PaddingChanged -= value; } } ////// ///[To be supplied.] ////// /// This is used for international applications where the language /// is written from RightToLeft. When this property is true, // and the RightToLeft is true, mirroring will be turned on on the form, and /// control placement and text will be from right to left. /// [ SRCategory(SR.CatAppearance), Localizable(true), DefaultValue(false), SRDescription(SR.ControlRightToLeftLayoutDescr) ] public virtual bool RightToLeftLayout { get { return rightToLeftLayout; } set { if (value != rightToLeftLayout) { rightToLeftLayout = value; using(new LayoutTransaction(this, this, PropertyNames.RightToLeftLayout)) { OnRightToLeftLayoutChanged(EventArgs.Empty); } } } } ////// /// The scroll rate for a month calendar control. The scroll /// rate is the number of months that the control moves its display /// when the user clicks a scroll button. If this value is zero, /// the month delta is reset to the default, which is the number of /// months displayed in the control. /// [ SRCategory(SR.CatBehavior), DefaultValue(DEFAULT_SCROLL_CHANGE), SRDescription(SR.MonthCalendarScrollChangeDescr) ] public int ScrollChange { get { return scrollChange; } set { if (scrollChange != value) { if (value < 0) { throw new ArgumentOutOfRangeException("ScrollChange", SR.GetString(SR.InvalidLowBoundArgumentEx, "ScrollChange", (value).ToString("D", CultureInfo.CurrentCulture), (0).ToString(CultureInfo.CurrentCulture))); } if (value > MaxScrollChange) { throw new ArgumentOutOfRangeException("ScrollChange", SR.GetString(SR.InvalidHighBoundArgumentEx, "ScrollChange", (value).ToString("D", CultureInfo.CurrentCulture), (MaxScrollChange).ToString("D", CultureInfo.CurrentCulture))); } if (IsHandleCreated) { SendMessage(NativeMethods.MCM_SETMONTHDELTA, value, 0); } scrollChange = value; } } } ////// /// [ SRCategory(SR.CatBehavior), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarSelectionEndDescr) ] public DateTime SelectionEnd { get { return selectionEnd; } set { if (selectionEnd != value) { // Keep SelectionEnd within min and max if (value < MinDate) { throw new ArgumentOutOfRangeException("SelectionEnd", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionEnd", FormatDate(value), "MinDate")); } if (value > MaxDate) { throw new ArgumentOutOfRangeException("SelectionEnd", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionEnd", FormatDate(value), "MaxDate")); } // If we've moved SelectionEnd before SelectionStart, move SelectionStart back if (selectionStart > value) { selectionStart = value; } // If we've moved SelectionEnd too far beyond SelectionStart, move SelectionStart forward if ((value - selectionStart).Days >= maxSelectionCount) { selectionStart = value.AddDays(1 - maxSelectionCount); } // Set the new selection range SetSelRange(selectionStart, value); } } } ///Indicates the end date of the selected range of dates. ////// /// [ SRCategory(SR.CatBehavior), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarSelectionStartDescr) ] public DateTime SelectionStart { get { return selectionStart; } set { if (selectionStart != value) { // Keep SelectionStart within min and max // if (value < minDate) { throw new ArgumentOutOfRangeException("SelectionStart", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionStart", FormatDate(value), "MinDate")); } if (value > maxDate) { throw new ArgumentOutOfRangeException("SelectionStart", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionStart", FormatDate(value), "MaxDate")); } // If we've moved SelectionStart beyond SelectionEnd, move SelectionEnd forward if (selectionEnd < value) { selectionEnd = value; } // If we've moved SelectionStart too far back from SelectionEnd, move SelectionEnd back if ((selectionEnd - value).Days >= maxSelectionCount) { selectionEnd = value.AddDays(maxSelectionCount - 1); } // Set the new selection range SetSelRange(value, selectionEnd); } } } ////// Indicates /// the start date of the selected range of dates. ////// /// Retrieves the selection range for a month calendar control. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarSelectionRangeDescr), Bindable(true) ] public SelectionRange SelectionRange { get { return new SelectionRange(SelectionStart, SelectionEnd); } set { SetSelectionRange(value.Start, value.End); } } ////// /// Indicates whether the month calendar control will display /// the "today" date at the bottom of the control. /// [ SRCategory(SR.CatBehavior), DefaultValue(true), SRDescription(SR.MonthCalendarShowTodayDescr) ] public bool ShowToday { get { return showToday; } set { if (showToday != value) { showToday = value; UpdateStyles(); AdjustSize(); } } } ////// /// Indicates whether the month calendar control will circle /// the "today" date. /// [ SRCategory(SR.CatBehavior), DefaultValue(true), SRDescription(SR.MonthCalendarShowTodayCircleDescr) ] public bool ShowTodayCircle { get { return showTodayCircle; } set { if (showTodayCircle != value) { showTodayCircle = value; UpdateStyles(); } } } ////// /// Indicates whether the month calendar control will the display /// week numbers (1-52) to the left of each row of days. /// [ SRCategory(SR.CatBehavior), Localizable(true), DefaultValue(false), SRDescription(SR.MonthCalendarShowWeekNumbersDescr) ] public bool ShowWeekNumbers { get { return showWeekNumbers; } set { if (showWeekNumbers != value) { showWeekNumbers = value; UpdateStyles(); AdjustSize(); } } } ////// /// The minimum size required to display a full month. The size /// information is presented in the form of a Point, with the x /// and y members representing the minimum width and height required /// for the control. The minimum required window size for a month calendar /// control depends on the currently selected font. /// [ SRCategory(SR.CatAppearance), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarSingleMonthSizeDescr) ] public Size SingleMonthSize { get { NativeMethods.RECT rect = new NativeMethods.RECT(); if (IsHandleCreated) { if ((int)SendMessage(NativeMethods.MCM_GETMINREQRECT, 0, ref rect) == 0) throw new InvalidOperationException(SR.GetString(SR.InvalidSingleMonthSize)); return new Size(rect.right, rect.bottom); } return DefaultSingleMonthSize; } } ////// /// Unlike most controls, serializing the MonthCalendar's Size is really bad: /// when it's restored at runtime, it uses a a default SingleMonthSize, which /// may not be right, especially for JPN/CHS machines. See VSWhidbey 527753. /// [ DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Localizable(false) ] public new Size Size { get { return base.Size; } set { base.Size = value; } } ////// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public override string Text { get { return base.Text; } set { base.Text = value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] new public event EventHandler TextChanged { add { base.TextChanged += value; } remove { base.TextChanged -= value; } } /// /// /// The date shown as "Today" in the Month Calendar control. /// By default, "Today" is the current date at the time /// the MonthCalendar control is created. /// [ SRCategory(SR.CatBehavior), SRDescription(SR.MonthCalendarTodayDateDescr) ] public DateTime TodayDate { get { if (todayDateSet) return todayDate; if (IsHandleCreated) { NativeMethods.SYSTEMTIME st = new NativeMethods.SYSTEMTIME(); int res = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_GETTODAY, 0, st); Debug.Assert(res != 0, "MCM_GETTODAY failed"); return DateTimePicker.SysTimeToDateTime(st).Date; } else return Now.Date; } set { if (!(todayDateSet) || (DateTime.Compare(value, todayDate) != 0)) { // throw if trying to set the TodayDate to a value greater than MaxDate if (DateTime.Compare(value, maxDate) > 0) { throw new ArgumentOutOfRangeException("TodayDate", SR.GetString(SR.InvalidHighBoundArgumentEx, "TodayDate", FormatDate(value), FormatDate(maxDate))); } // throw if trying to set the TodayDate to a value less than MinDate if (DateTime.Compare(value, minDate) < 0) { throw new ArgumentOutOfRangeException("TodayDate", SR.GetString(SR.InvalidLowBoundArgument, "TodayDate", FormatDate(value), FormatDate(minDate))); } todayDate = value.Date; todayDateSet = true; UpdateTodayDate(); } } } ////// /// Indicates whether or not the TodayDate property has been explicitly /// set by the user. If TodayDateSet is true, TodayDate will return whatever /// the user has set it to. If TodayDateSet is false, TodayDate will follow /// wall-clock time; ie. TodayDate will always equal the current system date. /// [ SRCategory(SR.CatBehavior), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), SRDescription(SR.MonthCalendarTodayDateSetDescr) ] public bool TodayDateSet { get { return todayDateSet; } } ////// /// The background color displayed in the month calendar's /// title. /// [ SRCategory(SR.CatAppearance), SRDescription(SR.MonthCalendarTitleBackColorDescr) ] public Color TitleBackColor { get { return titleBackColor; } set { if (value.IsEmpty) { throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "value")); } titleBackColor = value; SetControlColor(NativeMethods.MCSC_TITLEBK, value); } } ////// /// The foreground color used to display text within the month /// calendar's title. /// [ SRCategory(SR.CatAppearance), SRDescription(SR.MonthCalendarTitleForeColorDescr) ] public Color TitleForeColor { get { return titleForeColor; } set { if (value.IsEmpty) { throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "value")); } titleForeColor = value; SetControlColor(NativeMethods.MCSC_TITLETEXT, value); } } ////// /// The color used to display the previous and following months that /// appear on the current month calendar. /// [ SRCategory(SR.CatAppearance), SRDescription(SR.MonthCalendarTrailingForeColorDescr) ] public Color TrailingForeColor { get { return trailingForeColor; } set { if (value.IsEmpty) { throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "value")); } trailingForeColor = value; SetControlColor(NativeMethods.MCSC_TRAILINGTEXT, value); } } ////// /// Adds a day that will be bolded annually on the month calendar. /// Be sure to call updateBoldedDates() afterwards. /// public void AddAnnuallyBoldedDate(DateTime date) { annualArrayOfDates.Add(date); monthsOfYear[date.Month-1] |= 0x00000001<<(date.Day-1); } ////// /// Adds a day that will be bolded on the month calendar. /// Be sure to call updateBoldedDates() afterwards. /// public void AddBoldedDate(DateTime date) { if (!this.arrayOfDates.Contains(date)) { this.arrayOfDates.Add(date); } } ////// /// Adds a day that will be bolded monthly on the month calendar. /// Be sure to call updateBoldedDates() afterwards. /// public void AddMonthlyBoldedDate(DateTime date) { this.monthlyArrayOfDates.Add(date); datesToBoldMonthly |= 0x00000001<<(date.Day-1); } ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler Click { add { base.Click += value; } remove { base.Click -= value; } } /// /// /// [SRCategory(SR.CatAction), SRDescription(SR.MonthCalendarOnDateChangedDescr)] public event DateRangeEventHandler DateChanged { add { onDateChanged += value; } remove { onDateChanged -= value; } } ///[To be supplied.] ////// /// [SRCategory(SR.CatAction), SRDescription(SR.MonthCalendarOnDateSelectedDescr)] public event DateRangeEventHandler DateSelected { add { onDateSelected += value; } remove { onDateSelected -= value; } } ///[To be supplied.] ////// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event EventHandler DoubleClick { add { base.DoubleClick += value; } remove { base.DoubleClick -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event MouseEventHandler MouseClick { add { base.MouseClick += value; } remove { base.MouseClick -= value; } } /// /// [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event MouseEventHandler MouseDoubleClick { add { base.MouseDoubleClick += value; } remove { base.MouseDoubleClick -= value; } } /// /// /// MonthCalendar Onpaint. /// ///[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public new event PaintEventHandler Paint { add { base.Paint += value; } remove { base.Paint -= value; } } /// /// /// [SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftLayoutChangedDescr)] public event EventHandler RightToLeftLayoutChanged { add { onRightToLeftLayoutChanged += value; } remove { onRightToLeftLayoutChanged -= value; } } ///[To be supplied.] ////// /// Used to auto-size the control. The requested number of rows and columns are /// restricted by the maximum size of the parent control, hence the requested number /// of rows and columns may not be what you get. /// ///private void AdjustSize() { Size minSize = GetMinReqRect(); Size = minSize; } /// /// /// Event handler that bolds dates indicated by arrayOfDates /// ///private void BoldDates(DateBoldEventArgs e) { int months = e.Size; e.DaysToBold = new int[months]; SelectionRange range = GetDisplayRange(false); int startMonth = range.Start.Month; int startYear = range.Start.Year; int numDates = arrayOfDates.Count; for (int i=0; i = 0 && DateTime.Compare(date, range.End) <= 0) { int month = date.Month; int year = date.Year; int index = (year == startYear) ? month - startMonth : month + year*MONTHS_IN_YEAR - startYear*MONTHS_IN_YEAR - startMonth; e.DaysToBold[index] |= (0x00000001<<(date.Day-1)); } } //now we figure out which monthly and annual dates to bold --startMonth; for (int i=0; i /// /// Compares only the day and month of each time. /// ///private bool CompareDayAndMonth(DateTime t1, DateTime t2) { return(t1.Day == t2.Day && t1.Month == t2.Month); } /// /// /// ///protected override void CreateHandle() { if (!RecreatingHandle) { IntPtr userCookie = UnsafeNativeMethods.ThemingScope.Activate(); try { NativeMethods.INITCOMMONCONTROLSEX icc = new NativeMethods.INITCOMMONCONTROLSEX(); icc.dwICC = NativeMethods.ICC_DATE_CLASSES; SafeNativeMethods.InitCommonControlsEx(icc); } finally { UnsafeNativeMethods.ThemingScope.Deactivate(userCookie); } } base.CreateHandle(); } /// /// /// Called to cleanup a MonthCalendar. Normally you do not need /// to call this as the garbage collector will cleanup the buffer /// for you. However, there may be times when you may want to expedite /// the garbage collectors cleanup. /// protected override void Dispose(bool disposing) { if (mdsBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(mdsBuffer); mdsBuffer = IntPtr.Zero; } base.Dispose(disposing); } // Return a localized string representation of the given DateTime value. // Used for throwing exceptions, etc. // private static string FormatDate(DateTime value) { return value.ToString("d", CultureInfo.CurrentCulture); } ////// /// Retrieves date information that represents the low and high limits of the /// control's display. /// public SelectionRange GetDisplayRange(bool visible) { if (visible) return GetMonthRange(NativeMethods.GMR_VISIBLE); else return GetMonthRange(NativeMethods.GMR_DAYSTATE); } ////// /// Retrieves the enumeration value corresponding to the hit area. /// ///private HitArea GetHitArea(int hit) { switch (hit) { case NativeMethods.MCHT_TITLEBK: return HitArea.TitleBackground; case NativeMethods.MCHT_TITLEMONTH: return HitArea.TitleMonth; case NativeMethods.MCHT_TITLEYEAR: return HitArea.TitleYear; case NativeMethods.MCHT_TITLEBTNNEXT: return HitArea.NextMonthButton; case NativeMethods.MCHT_TITLEBTNPREV: return HitArea.PrevMonthButton; case NativeMethods.MCHT_CALENDARBK: return HitArea.CalendarBackground; case NativeMethods.MCHT_CALENDARDATE: return HitArea.Date; case NativeMethods.MCHT_CALENDARDATENEXT: return HitArea.NextMonthDate; case NativeMethods.MCHT_CALENDARDATEPREV: return HitArea.PrevMonthDate; case NativeMethods.MCHT_CALENDARDAY: return HitArea.DayOfWeek; case NativeMethods.MCHT_CALENDARWEEKNUM: return HitArea.WeekNumbers; case NativeMethods.MCHT_TODAYLINK: return HitArea.TodayLink; default: return HitArea.Nowhere; } } /// /// /// stub for getMinReqRect (int, boolean) /// ///private Size GetMinReqRect() { return GetMinReqRect(0, false, false); } /// /// /// Used internally to get the minimum size needed to display the /// MonthCalendar. This is needed because /// NativeMethods.MCM_GETMINREQRECT returns an incorrect value if showToday /// is set to false. If updateRows is true, then the /// number of rows will be updated according to height. /// ///private Size GetMinReqRect(int newDimensionLength, bool updateRows, bool updateCols) { Size minSize = SingleMonthSize; // Calculate calendar height // Size textExtent; using (WindowsFont font = WindowsFont.FromFont(this.Font)) { // this is the string that Windows uses to determine the extent of the today string textExtent = WindowsGraphicsCacheManager.MeasurementGraphics.GetTextExtent(DateTime.Now.ToShortDateString(), font); } int todayHeight = textExtent.Height + 4; // The constant 4 is from the comctl32 MonthCalendar source code int calendarHeight = minSize.Height; if (ShowToday) { // If ShowToday is true, then minSize already includes the height of the today string. // So we remove it to get the actual calendar height. // calendarHeight -= todayHeight; } if (updateRows) { Debug.Assert(calendarHeight > INSERT_HEIGHT_SIZE, "Divide by 0"); int nRows = (newDimensionLength - todayHeight + INSERT_HEIGHT_SIZE)/(calendarHeight + INSERT_HEIGHT_SIZE); this.dimensions.Height = (nRows < 1) ? 1 : nRows; } if (updateCols) { Debug.Assert(minSize.Width > INSERT_WIDTH_SIZE, "Divide by 0"); int nCols = (newDimensionLength - ExtraPadding)/minSize.Width; this.dimensions.Width = (nCols < 1) ? 1 : nCols; } minSize.Width = (minSize.Width + INSERT_WIDTH_SIZE) * dimensions.Width - INSERT_WIDTH_SIZE; minSize.Height = (calendarHeight + INSERT_HEIGHT_SIZE) * dimensions.Height - INSERT_HEIGHT_SIZE + todayHeight; // If the width we've calculated is too small to fit the Today string, enlarge the width to fit // if (IsHandleCreated) { int maxTodayWidth = (int)SendMessage(NativeMethods.MCM_GETMAXTODAYWIDTH, 0, 0); if (maxTodayWidth > minSize.Width) { minSize.Width = maxTodayWidth; } } // Fudge factor // minSize.Width += ExtraPadding; minSize.Height += ExtraPadding; return minSize; } /// /// /// ///private SelectionRange GetMonthRange(int flag) { NativeMethods.SYSTEMTIMEARRAY sa = new NativeMethods.SYSTEMTIMEARRAY(); SelectionRange range = new SelectionRange(); UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_GETMONTHRANGE, flag, sa); NativeMethods.SYSTEMTIME st = new NativeMethods.SYSTEMTIME(); st.wYear = sa.wYear1; st.wMonth = sa.wMonth1; st.wDayOfWeek = sa.wDayOfWeek1; st.wDay = sa.wDay1; range.Start = DateTimePicker.SysTimeToDateTime(st); st.wYear = sa.wYear2; st.wMonth = sa.wMonth2; st.wDayOfWeek = sa.wDayOfWeek2; st.wDay = sa.wDay2; range.End = DateTimePicker.SysTimeToDateTime(st); return range; } /// /// /// Called by setBoundsCore. If updateRows is true, then the /// number of rows will be updated according to height. /// ///private int GetPreferredHeight(int height, bool updateRows) { Size preferredSize = GetMinReqRect(height, updateRows, false); return preferredSize.Height; } /// /// /// Called by setBoundsCore. If updateCols is true, then the /// number of columns will be updated according to width. /// ///private int GetPreferredWidth(int width, bool updateCols) { Size preferredSize = GetMinReqRect(width, false, updateCols); return preferredSize.Width; } /// /// /// Determines which portion of a month calendar control is at /// at a given point on the screen. /// public HitTestInfo HitTest(int x, int y) { NativeMethods.MCHITTESTINFO mchi = new NativeMethods.MCHITTESTINFO(); mchi.pt_x = x; mchi.pt_y = y; mchi.cbSize = Marshal.SizeOf(typeof(NativeMethods.MCHITTESTINFO)); UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_HITTEST, 0, mchi); // If the hit area has an associated valid date, get it // HitArea hitArea = GetHitArea(mchi.uHit); if (HitTestInfo.HitAreaHasValidDateTime(hitArea)) { NativeMethods.SYSTEMTIME sys = new NativeMethods.SYSTEMTIME(); sys.wYear = mchi.st_wYear; sys.wMonth = mchi.st_wMonth; sys.wDayOfWeek = mchi.st_wDayOfWeek; sys.wDay = mchi.st_wDay; sys.wHour = mchi.st_wHour; sys.wMinute = mchi.st_wMinute; sys.wSecond = mchi.st_wSecond; sys.wMilliseconds = mchi.st_wMilliseconds; return new HitTestInfo(new Point(mchi.pt_x, mchi.pt_y), hitArea, DateTimePicker.SysTimeToDateTime(sys)); } else { return new HitTestInfo(new Point(mchi.pt_x, mchi.pt_y), hitArea); } } ////// /// Determines which portion of a month calendar control is at /// at a given point on the screen. /// public HitTestInfo HitTest(Point point) { return HitTest(point.X, point.Y); } ////// /// Handling special input keys, such as pgup, pgdown, home, end, etc... /// protected override bool IsInputKey(Keys keyData) { if ((keyData & Keys.Alt) == Keys.Alt) return false; switch (keyData & Keys.KeyCode) { case Keys.PageUp: case Keys.PageDown: case Keys.Home: case Keys.End: return true; } return base.IsInputKey(keyData); } ////// /// Overrides Control.OnHandleCreated() /// ///protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); SetSelRange(selectionStart, selectionEnd); if (maxSelectionCount != DEFAULT_MAX_SELECTION_COUNT) { SendMessage(NativeMethods.MCM_SETMAXSELCOUNT, maxSelectionCount, 0); } AdjustSize(); if (todayDateSet) { NativeMethods.SYSTEMTIME st = DateTimePicker.DateTimeToSysTime(todayDate); UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETTODAY, 0, st); } SetControlColor(NativeMethods.MCSC_TEXT, ForeColor); SetControlColor(NativeMethods.MCSC_MONTHBK, BackColor); SetControlColor(NativeMethods.MCSC_TITLEBK, titleBackColor); SetControlColor(NativeMethods.MCSC_TITLETEXT, titleForeColor); SetControlColor(NativeMethods.MCSC_TRAILINGTEXT, trailingForeColor); int firstDay; if (firstDayOfWeek == Day.Default) { firstDay = NativeMethods.LOCALE_IFIRSTDAYOFWEEK; } else { firstDay = (int)firstDayOfWeek; } SendMessage(NativeMethods.MCM_SETFIRSTDAYOFWEEK, 0, firstDay); SetRange(); if (scrollChange != DEFAULT_SCROLL_CHANGE) { SendMessage(NativeMethods.MCM_SETMONTHDELTA, scrollChange, 0); } SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.MarshaledUserPreferenceChanged); } /// /// /// Overrides Control.OnHandleDestroyed() /// ///protected override void OnHandleDestroyed(EventArgs e) { SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.MarshaledUserPreferenceChanged); base.OnHandleDestroyed(e); } /// /// /// Fires the event indicating that the currently selected date /// or range of dates has changed. /// protected virtual void OnDateChanged(DateRangeEventArgs drevent) { if (onDateChanged != null) { onDateChanged(this, drevent); } } ////// /// Fires the event indicating that the user has changed his\her selection. /// protected virtual void OnDateSelected(DateRangeEventArgs drevent) { if (onDateSelected != null) { onDateSelected(this, drevent); } } ////// /// protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); AdjustSize(); } ///[To be supplied.] ////// /// protected override void OnForeColorChanged(EventArgs e) { base.OnForeColorChanged(e); SetControlColor(NativeMethods.MCSC_TEXT, ForeColor); } ///[To be supplied.] ////// /// protected override void OnBackColorChanged(EventArgs e) { base.OnBackColorChanged(e); SetControlColor(NativeMethods.MCSC_MONTHBK, BackColor); } ///[To be supplied.] ////// /// [EditorBrowsable(EditorBrowsableState.Advanced)] protected virtual void OnRightToLeftLayoutChanged(EventArgs e) { if (GetAnyDisposingInHierarchy()) { return; } if (RightToLeft == RightToLeft.Yes) { RecreateHandle(); } if (onRightToLeftLayoutChanged != null) { onRightToLeftLayoutChanged(this, e); } } ///[To be supplied.] ////// /// Removes all annually bolded days. Be sure to call updateBoldedDates() afterwards. /// public void RemoveAllAnnuallyBoldedDates() { this.annualArrayOfDates.Clear(); for (int i=0; i/// /// Removes all the bolded days. Be sure to call updateBoldedDates() afterwards. /// public void RemoveAllBoldedDates() { this.arrayOfDates.Clear(); } ////// /// Removes all monthly bolded days. Be sure to call updateBoldedDates() afterwards. /// public void RemoveAllMonthlyBoldedDates() { this.monthlyArrayOfDates.Clear(); datesToBoldMonthly = 0; } ////// /// Removes an annually bolded date. If the date is not found in the /// bolded date list, then no action is taken. If date occurs more than /// once in the bolded date list, then only the first date is removed. When /// comparing dates, only the day and month are used. Be sure to call /// updateBoldedDates afterwards. /// public void RemoveAnnuallyBoldedDate(DateTime date) { int length = annualArrayOfDates.Count; int i=0; for (; i/// /// Removes a bolded date. If the date is not found in the /// bolded date list, then no action is taken. If date occurs more than /// once in the bolded date list, then only the first date is removed. /// Be sure to call updateBoldedDates() afterwards. /// public void RemoveBoldedDate(DateTime date) { int length = arrayOfDates.Count; for (int i=0; i/// /// Removes a monthly bolded date. If the date is not found in the /// bolded date list, then no action is taken. If date occurs more than /// once in the bolded date list, then only the first date is removed. When /// comparing dates, only the day and month are used. Be sure to call /// updateBoldedDates afterwards. /// public void RemoveMonthlyBoldedDate(DateTime date) { int length = monthlyArrayOfDates.Count; int i=0; for (; i/// /// Resets the maximum selectable date. By default value, there is no /// upper limit. /// private void ResetMaxDate() { MaxDate = DateTime.MaxValue; } ////// /// Resets the minimum selectable date. By default value, there is no /// lower limit. /// private void ResetMinDate() { MinDate = DateTime.MinValue; } private void ResetMonthlyBoldedDates() { monthlyArrayOfDates.Clear(); } ////// /// Resets the limits of the selection range. By default value, the upper /// and lower limit is the current date. /// private void ResetSelectionRange() { SetSelectionRange(Now, Now); } private void ResetTrailingForeColor() { TrailingForeColor = DEFAULT_TRAILING_FORE_COLOR; } private void ResetTitleForeColor() { TitleForeColor = DEFAULT_TITLE_FORE_COLOR; } private void ResetTitleBackColor() { TitleBackColor = DEFAULT_TITLE_BACK_COLOR; } ////// /// Resets the "today"'s date. By default value, "today" is the /// current date (and is automatically updated when the clock crosses /// over to the next day). /// If you set the today date yourself (using the TodayDate property) /// the control will no longer automatically update the current day /// for you. To re-enable this behavior, ResetTodayDate() is used. /// private void ResetTodayDate() { todayDateSet = false; UpdateTodayDate(); } ////// /// reqSize = # elements in int[] array /// /// The size argument should be greater than 0. /// Because of the nature of MonthCalendar, we can expect that /// the requested size will not be ridiculously large, hence /// it is not necessary to decrease the size of an allocated /// block if the new requested size is smaller. /// ///private IntPtr RequestBuffer(int reqSize) { Debug.Assert(reqSize > 0, "Requesting a ridiculously small buffer"); int intSize = 4; // if the current buffer size is insufficient... if (reqSize * intSize > mdsBufferSize) { // free and expand the buffer, if (mdsBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(mdsBuffer); mdsBuffer = IntPtr.Zero; } // Round up to the nearest multiple of MINIMUM_ALLOC_SIZE float quotient = (float) (reqSize-1) / MINIMUM_ALLOC_SIZE; int actualSize = ((int) (quotient+1)) * MINIMUM_ALLOC_SIZE; Debug.Assert(actualSize >= reqSize, "Tried to round up, but got it wrong"); mdsBufferSize = actualSize * intSize; mdsBuffer = Marshal.AllocHGlobal(mdsBufferSize); return mdsBuffer; } return mdsBuffer; } /// /// /// Overrides Control.SetBoundsCore to enforce auto-sizing. /// ///protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { Rectangle oldBounds = Bounds; Size max = SystemInformation.MaxWindowTrackSize; if (width != oldBounds.Width) { if (width > max.Width) width = max.Width; width = GetPreferredWidth(width, true); } if (height != oldBounds.Height) { if (height > max.Height) height = max.Height; height = GetPreferredHeight(height, true); } base.SetBoundsCore(x, y, width, height, specified); } /// /// /// If the handle has been created, this applies the color to the control /// ///private void SetControlColor(int colorIndex, Color value) { if (IsHandleCreated) { SendMessage(NativeMethods.MCM_SETCOLOR, colorIndex, ColorTranslator.ToWin32(value)); } } /// /// /// Updates the window handle with the min/max ranges if it has been /// created. /// ///private void SetRange() { SetRange(DateTimePicker.EffectiveMinDate(minDate), DateTimePicker.EffectiveMaxDate(maxDate)); } private void SetRange(DateTime minDate, DateTime maxDate) { // Keep selection range within passed in minDate and maxDate if (selectionStart < minDate) { selectionStart = minDate; } if (selectionStart > maxDate) { selectionStart = maxDate; } if (selectionEnd < minDate) { selectionEnd = minDate; } if (selectionEnd > maxDate) { selectionEnd = maxDate; } SetSelRange(selectionStart, selectionEnd); // Updated the calendar range // if (IsHandleCreated) { int flag = 0; NativeMethods.SYSTEMTIMEARRAY sa = new NativeMethods.SYSTEMTIMEARRAY(); flag |= NativeMethods.GDTR_MIN | NativeMethods.GDTR_MAX; NativeMethods.SYSTEMTIME sys = DateTimePicker.DateTimeToSysTime(minDate); sa.wYear1 = sys.wYear; sa.wMonth1 = sys.wMonth; sa.wDayOfWeek1 = sys.wDayOfWeek; sa.wDay1 = sys.wDay; sys = DateTimePicker.DateTimeToSysTime(maxDate); sa.wYear2 = sys.wYear; sa.wMonth2 = sys.wMonth; sa.wDayOfWeek2 = sys.wDayOfWeek; sa.wDay2 = sys.wDay; if ((int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETRANGE, flag, sa) == 0) throw new InvalidOperationException(SR.GetString(SR.MonthCalendarRange, minDate.ToShortDateString(), maxDate.ToShortDateString())); } } /// /// /// Sets the number of columns and rows to display. /// public void SetCalendarDimensions(int x, int y) { if (x < 1) { throw new ArgumentOutOfRangeException("x", SR.GetString(SR.MonthCalendarInvalidDimensions, (x).ToString("D", CultureInfo.CurrentCulture), (y).ToString("D", CultureInfo.CurrentCulture))); } if (y < 1) { throw new ArgumentOutOfRangeException("y", SR.GetString(SR.MonthCalendarInvalidDimensions, (x).ToString("D", CultureInfo.CurrentCulture), (y).ToString("D", CultureInfo.CurrentCulture))); } // MonthCalendar limits the dimensions to x * y <= 12 // i.e. a maximum of twelve months can be displayed at a time // The following code emulates what is done inside monthcalendar (in comctl32.dll): // The dimensions are gradually reduced until the inequality above holds. // while (x * y > 12) { if (x > y) { x--; } else { y--; } } if (dimensions.Width != x || dimensions.Height != y) { this.dimensions.Width = x; this.dimensions.Height = y; AdjustSize(); } } ////// /// Sets date as the current selected date. The start and begin of /// the selection range will both be equal to date. /// public void SetDate(DateTime date) { if (date.Ticks < minDate.Ticks) { throw new ArgumentOutOfRangeException("date", SR.GetString(SR.InvalidLowBoundArgumentEx, "date", FormatDate(date), "MinDate")); } if (date.Ticks > maxDate.Ticks) { throw new ArgumentOutOfRangeException("date", SR.GetString(SR.InvalidHighBoundArgumentEx, "date", FormatDate(date), "MaxDate")); } SetSelectionRange(date, date); } ////// /// Sets the selection for a month calendar control to a given date range. /// The selection range will not be set if the selection range exceeds the /// maximum selection count. /// public void SetSelectionRange(DateTime date1, DateTime date2) { // Keep the dates within the min and max dates if (date1.Ticks < minDate.Ticks) { throw new ArgumentOutOfRangeException("date1", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionStart", FormatDate(date1), "MinDate")); } if (date1.Ticks > maxDate.Ticks) { throw new ArgumentOutOfRangeException("date1", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionEnd", FormatDate(date1), "MaxDate")); } if (date2.Ticks < minDate.Ticks) { throw new ArgumentOutOfRangeException("date2", SR.GetString(SR.InvalidLowBoundArgumentEx, "SelectionStart", FormatDate(date2), "MinDate")); } if (date2.Ticks > maxDate.Ticks) { throw new ArgumentOutOfRangeException("date2", SR.GetString(SR.InvalidHighBoundArgumentEx, "SelectionEnd", FormatDate(date2), "MaxDate")); } // If date1 > date2, we just select date2 (compat) // if (date1 > date2) { date2 = date1; } // If the range exceeds maxSelectionCount, compare with the previous range and adjust whichever // limit hasn't changed. // if ((date2 - date1).Days >= maxSelectionCount) { if (date1.Ticks == selectionStart.Ticks) { // Bring start date forward // date1 = date2.AddDays(1 - maxSelectionCount); } else { // Bring end date back // date2 = date1.AddDays(maxSelectionCount - 1); } } // Set the range SetSelRange(date1, date2); } ////// /// Upper must be greater than Lower /// ///private void SetSelRange(DateTime lower, DateTime upper) { Debug.Assert(lower.Ticks <= upper.Ticks, "lower must be less than upper"); bool changed = false; if (selectionStart != lower || selectionEnd != upper) { changed = true; selectionStart = lower; selectionEnd = upper; } // always set the value on the control, to ensure that // it is up to date. // if (IsHandleCreated) { NativeMethods.SYSTEMTIMEARRAY sa = new NativeMethods.SYSTEMTIMEARRAY(); NativeMethods.SYSTEMTIME sys = DateTimePicker.DateTimeToSysTime(lower); sa.wYear1 = sys.wYear; sa.wMonth1 = sys.wMonth; sa.wDayOfWeek1 = sys.wDayOfWeek; sa.wDay1 = sys.wDay; sys = DateTimePicker.DateTimeToSysTime(upper); sa.wYear2 = sys.wYear; sa.wMonth2 = sys.wMonth; sa.wDayOfWeek2 = sys.wDayOfWeek; sa.wDay2 = sys.wDay; UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETSELRANGE , 0, sa); } if (changed) { OnDateChanged(new DateRangeEventArgs(lower, upper)); } } private bool ShouldSerializeAnnuallyBoldedDates() { return annualArrayOfDates.Count > 0; } private bool ShouldSerializeBoldedDates() { return arrayOfDates.Count > 0; } private bool ShouldSerializeCalendarDimensions() { return !dimensions.Equals(new Size(1, 1)); } private bool ShouldSerializeTrailingForeColor() { return !TrailingForeColor.Equals(DEFAULT_TRAILING_FORE_COLOR); } private bool ShouldSerializeTitleForeColor() { return !TitleForeColor.Equals(DEFAULT_TITLE_FORE_COLOR); } private bool ShouldSerializeTitleBackColor() { return !TitleBackColor.Equals(DEFAULT_TITLE_BACK_COLOR); } private bool ShouldSerializeMonthlyBoldedDates() { return monthlyArrayOfDates.Count > 0; } /// /// /// Retrieves true if the maxDate should be persisted in code gen. /// private bool ShouldSerializeMaxDate() { return maxDate != DateTimePicker.MaximumDateTime && maxDate != DateTime.MaxValue; } ////// /// Retrieves true if the minDate should be persisted in code gen. /// private bool ShouldSerializeMinDate() { return minDate != DateTimePicker.MinimumDateTime && minDate != DateTime.MinValue; } ////// /// Retrieves true if the selectionRange should be persisted in code gen. /// private bool ShouldSerializeSelectionRange() { return !DateTime.Equals(selectionEnd, selectionStart); } ////// /// Retrieves true if the todayDate should be persisted in code gen. /// private bool ShouldSerializeTodayDate() { return todayDateSet; } ////// /// Returns a string representation for this control. /// ///public override string ToString() { string s = base.ToString(); return s + ", " + SelectionRange.ToString(); } /// /// /// Forces month calendar to display the current set of bolded dates. /// public void UpdateBoldedDates() { RecreateHandle(); } ////// /// Updates the current setting for "TODAY" in the MonthCalendar control /// If the today date is set, the control will be set to that. Otherwise, /// it will be set to null (running clock mode - the today date will be /// automatically updated). /// private void UpdateTodayDate() { if (IsHandleCreated) { NativeMethods.SYSTEMTIME st = null; if (todayDateSet) { st = DateTimePicker.DateTimeToSysTime(todayDate); } UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.MCM_SETTODAY, 0, st); } } private void MarshaledUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs pref) { try { //use begininvoke instead of invoke in case the destination thread is not processing messages. BeginInvoke(new UserPreferenceChangedEventHandler(this.UserPreferenceChanged), new object[] { sender, pref }); } catch (InvalidOperationException) { } //if the destination thread does not exist, don't send. } private void UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs pref) { if (pref.Category == UserPreferenceCategory.Locale) { // We need to recreate the monthcalendar handle when the locale changes, because // the day names etc. are only updated on a handle recreate (comctl32 limitation). // RecreateHandle(); } } ////// /// Handles the MCN_SELCHANGE notification /// ///private void WmDateChanged(ref Message m) { NativeMethods.NMSELCHANGE nmmcsc = (NativeMethods.NMSELCHANGE)m.GetLParam(typeof(NativeMethods.NMSELCHANGE)); DateTime start = selectionStart = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelStart); DateTime end = selectionEnd = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelEnd); //subhag if (start.Ticks < minDate.Ticks || end.Ticks < minDate.Ticks) SetSelRange(minDate,minDate); else if (start.Ticks > maxDate.Ticks || end.Ticks > maxDate.Ticks) SetSelRange(maxDate,maxDate); //end subhag OnDateChanged(new DateRangeEventArgs(start, end)); } /// /// /// Handles the MCN_GETDAYSTATE notification /// ///private void WmDateBold(ref Message m) { NativeMethods.NMDAYSTATE nmmcds = (NativeMethods.NMDAYSTATE)m.GetLParam(typeof(NativeMethods.NMDAYSTATE)); DateTime start = DateTimePicker.SysTimeToDateTime(nmmcds.stStart); DateBoldEventArgs boldEvent = new DateBoldEventArgs(start, nmmcds.cDayState); BoldDates(boldEvent); mdsBuffer = RequestBuffer(boldEvent.Size); // copy boldEvent into mdsBuffer Marshal.Copy(boldEvent.DaysToBold, 0, mdsBuffer, boldEvent.Size); // now we replug DateBoldEventArgs info into NMDAYSTATE nmmcds.prgDayState = mdsBuffer; Marshal.StructureToPtr(nmmcds, m.LParam, false); } /// /// /// Handles the MCN_SELECT notification /// ///private void WmDateSelected(ref Message m) { NativeMethods.NMSELCHANGE nmmcsc = (NativeMethods.NMSELCHANGE)m.GetLParam(typeof(NativeMethods.NMSELCHANGE)); DateTime start = selectionStart = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelStart); DateTime end = selectionEnd = DateTimePicker.SysTimeToDateTime(nmmcsc.stSelEnd); //subhag if (start.Ticks < minDate.Ticks || end.Ticks < minDate.Ticks) SetSelRange(minDate,minDate); else if (start.Ticks > maxDate.Ticks || end.Ticks > maxDate.Ticks) SetSelRange(maxDate,maxDate); //end subhag OnDateSelected(new DateRangeEventArgs(start, end)); } /// /// /// Handles the WM_GETDLGCODE message /// ///private void WmGetDlgCode(ref Message m) { // The MonthCalendar does its own handling of arrow keys m.Result = (IntPtr)NativeMethods.DLGC_WANTARROWS; } /// /// /// Handles the WM_COMMAND messages reflected from the parent control. /// ///private void WmReflectCommand(ref Message m) { if (m.HWnd == Handle) { NativeMethods.NMHDR nmhdr = (NativeMethods.NMHDR)m.GetLParam(typeof(NativeMethods.NMHDR)); switch (nmhdr.code) { case NativeMethods.MCN_SELECT: WmDateSelected(ref m); break; case NativeMethods.MCN_SELCHANGE: WmDateChanged(ref m); break; case NativeMethods.MCN_GETDAYSTATE: WmDateBold(ref m); break; } } } /// /// /// Overrided wndProc /// ///[SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeMethods.WM_LBUTTONDOWN: FocusInternal(); if (!ValidationCancelled) { base.WndProc(ref m); } break; case NativeMethods.WM_GETDLGCODE: WmGetDlgCode(ref m); break; case NativeMethods.WM_REFLECT + NativeMethods.WM_NOTIFY: WmReflectCommand(ref m); base.WndProc(ref m); break; default: base.WndProc(ref m); break; } } /// /// /// HitTestInfo objects are returned by MonthCalendar in response to the hitTest method. /// HitTestInfo is for informational purposes only; the user should not construct these objects, and /// cannot modify any of the members. /// public sealed class HitTestInfo { readonly Point point; readonly HitArea hitArea; readonly DateTime time; ////// /// ///internal HitTestInfo(Point pt, HitArea area, DateTime time) { this.point = pt; this.hitArea = area; this.time = time; } /// /// /// This constructor is used when the DateTime member is invalid. /// ///internal HitTestInfo(Point pt, HitArea area) { this.point = pt; this.hitArea = area; } /// /// /// The point that was hit-tested /// public Point Point { get { return point; } } ////// /// Output member that receives an enumeration value from System.Windows.Forms.MonthCalendar.HitArea /// representing the result of the hit-test operation. /// public HitArea HitArea { get { return hitArea; } } ////// /// The time information specific to the location that was hit-tested. This value /// will only be valid at certain values of hitArea. /// public DateTime Time { get { return time; } } ////// /// Determines whether a given HitArea should have a corresponding valid DateTime /// ///internal static bool HitAreaHasValidDateTime(HitArea hitArea) { switch (hitArea) { case HitArea.Date: //case HitArea.DayOfWeek: comCtl does not provide a valid date case HitArea.WeekNumbers: return true; } return false; } } /// /// /// This enumeration has specific areas of the MonthCalendar control as its enumerated values. /// The hitArea member of System.Windows.Forms.Win32.HitTestInfo will be one of these enumerated values, and /// indicates which portion of a month calendar is under a specific point. /// public enum HitArea { ////// /// The given point was not on the month calendar control, or it was in an inactive portion of the control. /// Nowhere = 0, ////// /// The given point was over the background of a month's title /// TitleBackground = 1, ////// /// The given point was in a month's title bar, over a month name /// TitleMonth = 2, ////// /// The given point was in a month's title bar, over the year value /// TitleYear = 3, ////// /// The given point was over the button at the top right corner of the control. /// If the user clicks here, the month calendar will scroll its display to the next /// month or set of months /// NextMonthButton = 4, ////// /// The given point was over the button at the top left corner of the control. If the /// user clicks here, the month calendar will scroll its display to the previous month /// or set of months /// PrevMonthButton = 5, ////// /// The given point was in the calendar's background /// CalendarBackground = 6, ////// /// The given point was on a particular date within the calendar, and the time member of /// HitTestInfo will be set to the date at the given point. /// Date = 7, ////// /// The given point was over a date from the next month (partially displayed at the end of /// the currently displayed month). If the user clicks here, the month calendar will scroll /// its display to the next month or set of months. /// NextMonthDate = 8, ////// /// The given point was over a date from the previous month (partially displayed at the end /// of the currently displayed month). If the user clicks here, the month calendar will scroll /// its display to the previous month or set of months. /// PrevMonthDate = 9, ////// /// The given point was over a day abbreviation ("Fri", for example). The time member /// of HitTestInfo will be set to the corresponding date on the top row. /// DayOfWeek = 10, ////// /// The given point was over a week number. This will only occur if the showWeekNumbers /// property of MonthCalendar is enabled. The time member of HitTestInfo will be set to /// the corresponding date in the leftmost column. /// WeekNumbers = 11, ////// /// The given point was on the "today" link at the bottom of the month calendar control /// TodayLink = 12, } } // end class MonthCalendar } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlConnection.cs
- WinInet.cs
- FaultContext.cs
- GenericEnumConverter.cs
- PopupRootAutomationPeer.cs
- InheritanceRules.cs
- ObjectItemCollection.cs
- Wildcard.cs
- XPathScanner.cs
- ToolStripDropDownClosingEventArgs.cs
- SqlConnectionPoolProviderInfo.cs
- VersionPair.cs
- WorkflowOperationInvoker.cs
- EntityContainerAssociationSet.cs
- SafeHandles.cs
- MatrixTransform3D.cs
- XmlAttributeAttribute.cs
- ExtensibleClassFactory.cs
- SoapInteropTypes.cs
- CallbackValidatorAttribute.cs
- StopStoryboard.cs
- DragEvent.cs
- TableRowGroup.cs
- OdbcHandle.cs
- WorkflowMessageEventHandler.cs
- NetCodeGroup.cs
- PrinterUnitConvert.cs
- CollectionEditorDialog.cs
- DescendantQuery.cs
- CompareValidator.cs
- TransformerConfigurationWizardBase.cs
- TreeViewBindingsEditorForm.cs
- Debug.cs
- TableLayoutSettingsTypeConverter.cs
- ControlParser.cs
- SimpleLine.cs
- WebPartEditorApplyVerb.cs
- SchemaManager.cs
- CannotUnloadAppDomainException.cs
- KnownTypesProvider.cs
- CollectionViewGroupInternal.cs
- DataKeyArray.cs
- DisplayToken.cs
- WebUtil.cs
- Odbc32.cs
- PropertyDescriptorGridEntry.cs
- CryptoProvider.cs
- UrlMappingsSection.cs
- TrustLevelCollection.cs
- GenericPrincipal.cs
- BindingOperations.cs
- DefaultProxySection.cs
- PipelineModuleStepContainer.cs
- RuntimeCompatibilityAttribute.cs
- PriorityQueue.cs
- DBSqlParserTable.cs
- CodeVariableReferenceExpression.cs
- WebPartExportVerb.cs
- ColorContextHelper.cs
- SignedInfo.cs
- XmlDataDocument.cs
- AsyncResult.cs
- ObjectContext.cs
- Visitor.cs
- ArraySortHelper.cs
- SecurityException.cs
- StaticSiteMapProvider.cs
- CodePropertyReferenceExpression.cs
- TrackingServices.cs
- _NetworkingPerfCounters.cs
- DataGridViewCellStyleEditor.cs
- ParamArrayAttribute.cs
- FeatureAttribute.cs
- Hash.cs
- RowUpdatedEventArgs.cs
- ReferencedType.cs
- SettingsAttributes.cs
- RC2.cs
- XPathAxisIterator.cs
- ProfilePropertySettingsCollection.cs
- MemberPathMap.cs
- GridViewDeletedEventArgs.cs
- NotifyIcon.cs
- GridViewEditEventArgs.cs
- SmtpLoginAuthenticationModule.cs
- While.cs
- FixedSOMTable.cs
- TextureBrush.cs
- ImageListDesigner.cs
- BamlBinaryReader.cs
- ApplicationActivator.cs
- MenuStrip.cs
- PointConverter.cs
- DataViewSetting.cs
- RangeValuePattern.cs
- SpoolingTaskBase.cs
- FloaterBaseParagraph.cs
- UnionExpr.cs
- DependentList.cs
- AdRotatorDesigner.cs