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:
///
/// 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.
///
[
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;
///
///
/// 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; i 0) {
//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();
}
}
///
///
/// [To be supplied.]
///
[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;
}
}
///
///
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler BackgroundImageChanged {
add {
base.BackgroundImageChanged += value;
}
remove {
base.BackgroundImageChanged -= value;
}
}
///
///
/// [To be supplied.]
///
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public override ImageLayout BackgroundImageLayout {
get {
return base.BackgroundImageLayout;
}
set {
base.BackgroundImageLayout = value;
}
}
///
///
[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);
}
}
}
}
}
///
///
/// [To be supplied.]
///
[SRDescription(SR.MonthCalendarForeColorDescr)]
public override Color ForeColor {
get {
if (ShouldSerializeForeColor()) {
return base.ForeColor;
}
else {
return SystemColors.WindowText;
}
}
set {
base.ForeColor = value;
}
}
///
[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;
}
}
///
///
///
/// [To be supplied.]
///
///
[
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; }
}
///
///
/// 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;
}
}
}
///
///
/// Indicates the end date of the selected range of dates.
///
[
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 start 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);
}
}
}
///
///
/// 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;
}
}
///
///
/// [To be supplied.]
///
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
get {
return base.Text;
}
set {
base.Text = value;
}
}
///
///
[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;
}
}
///
///
/// [To be supplied.]
///
[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;
}
}
///
///
[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;
}
}
///
///
/// [To be supplied.]
///
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftLayoutChangedDescr)]
public event EventHandler RightToLeftLayoutChanged {
add {
onRightToLeftLayoutChanged += value;
}
remove {
onRightToLeftLayoutChanged -= value;
}
}
///
///
/// 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);
}
}
///
///
/// [To be supplied.]
///
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);
}
}
///
///
/// 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:
///
/// 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.
///
[
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;
///
///
/// 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; i 0) {
//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();
}
}
///
///
/// [To be supplied.]
///
[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;
}
}
///
///
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler BackgroundImageChanged {
add {
base.BackgroundImageChanged += value;
}
remove {
base.BackgroundImageChanged -= value;
}
}
///
///
/// [To be supplied.]
///
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public override ImageLayout BackgroundImageLayout {
get {
return base.BackgroundImageLayout;
}
set {
base.BackgroundImageLayout = value;
}
}
///
///
[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);
}
}
}
}
}
///
///
/// [To be supplied.]
///
[SRDescription(SR.MonthCalendarForeColorDescr)]
public override Color ForeColor {
get {
if (ShouldSerializeForeColor()) {
return base.ForeColor;
}
else {
return SystemColors.WindowText;
}
}
set {
base.ForeColor = value;
}
}
///
[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;
}
}
///
///
///
/// [To be supplied.]
///
///
[
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; }
}
///
///
/// 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;
}
}
}
///
///
/// Indicates the end date of the selected range of dates.
///
[
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 start 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);
}
}
}
///
///
/// 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;
}
}
///
///
/// [To be supplied.]
///
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
get {
return base.Text;
}
set {
base.Text = value;
}
}
///
///
[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;
}
}
///
///
/// [To be supplied.]
///
[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;
}
}
///
///
[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;
}
}
///
///
/// [To be supplied.]
///
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftLayoutChangedDescr)]
public event EventHandler RightToLeftLayoutChanged {
add {
onRightToLeftLayoutChanged += value;
}
remove {
onRightToLeftLayoutChanged -= value;
}
}
///
///
/// 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);
}
}
///
///
/// [To be supplied.]
///
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);
}
}
///
///
/// 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
- ObjectSet.cs
- FieldToken.cs
- HtmlInputRadioButton.cs
- BitmapCache.cs
- CustomSignedXml.cs
- ImageDrawing.cs
- SortExpressionBuilder.cs
- SqlTopReducer.cs
- EventSinkActivityDesigner.cs
- HttpHeaderCollection.cs
- CodeArrayCreateExpression.cs
- ObjectQuery_EntitySqlExtensions.cs
- NullableDecimalAverageAggregationOperator.cs
- adornercollection.cs
- Accessors.cs
- XDRSchema.cs
- DrawingCollection.cs
- MenuItemAutomationPeer.cs
- SeparatorAutomationPeer.cs
- RangeContentEnumerator.cs
- NameNode.cs
- PackageDigitalSignature.cs
- SchemaMapping.cs
- StylusTip.cs
- ToolboxCategory.cs
- EditorPart.cs
- ExternalException.cs
- Polygon.cs
- DispatchChannelSink.cs
- WebHttpSecurity.cs
- StylusLogic.cs
- FixedFlowMap.cs
- ByteStorage.cs
- ContainerVisual.cs
- EdgeModeValidation.cs
- CryptoKeySecurity.cs
- MSAANativeProvider.cs
- ContextProperty.cs
- DefaultTraceListener.cs
- XmlParserContext.cs
- RadioButtonStandardAdapter.cs
- DataGridViewRowCancelEventArgs.cs
- Win32.cs
- CapabilitiesSection.cs
- SafeCancelMibChangeNotify.cs
- OLEDB_Enum.cs
- DBBindings.cs
- IDReferencePropertyAttribute.cs
- NullReferenceException.cs
- clipboard.cs
- exports.cs
- PropertyPathWorker.cs
- ScrollViewerAutomationPeer.cs
- WebConfigurationHostFileChange.cs
- FixedDocumentSequencePaginator.cs
- ChildrenQuery.cs
- DataKeyCollection.cs
- Empty.cs
- XPathQilFactory.cs
- RangeBase.cs
- FtpWebResponse.cs
- SqlDataSourceEnumerator.cs
- ServiceHttpModule.cs
- SafeEventLogWriteHandle.cs
- RelatedView.cs
- OAVariantLib.cs
- BaseParser.cs
- SplitContainerDesigner.cs
- NamedElement.cs
- FilteredSchemaElementLookUpTable.cs
- TabletDeviceInfo.cs
- WindowsSlider.cs
- SettingsPropertyNotFoundException.cs
- UnhandledExceptionEventArgs.cs
- ProvidersHelper.cs
- TextBounds.cs
- XamlContextStack.cs
- AdPostCacheSubstitution.cs
- ImageCollectionCodeDomSerializer.cs
- IgnoreFileBuildProvider.cs
- WindowHideOrCloseTracker.cs
- TransportSecurityHelpers.cs
- TextHidden.cs
- WebSysDisplayNameAttribute.cs
- HttpValueCollection.cs
- Process.cs
- ZipIOLocalFileDataDescriptor.cs
- TemplateBuilder.cs
- XmlValidatingReader.cs
- CodeConstructor.cs
- ApplicationInterop.cs
- WebPartMinimizeVerb.cs
- DbMetaDataFactory.cs
- LocalizedNameDescriptionPair.cs
- Funcletizer.cs
- XmlBinaryReaderSession.cs
- PreviewPageInfo.cs
- FontFaceLayoutInfo.cs
- SmiGettersStream.cs
- HitTestWithPointDrawingContextWalker.cs