|
//------------------------------------------------------------------------------
// <copyright file="MonthCalendar.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
*/
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;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar"]/*' />
/// <devdoc>
/// 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:
/// <code>
/// 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);
/// </code>
/// Removal of all bolded dates is accomplished with:
/// <code>
/// mc.removeAllBoldedDates();
/// </code>
/// 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:
/// <code>
/// 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();
/// </code>
/// The same applies to addition and removal of annual and monthly bolded dates.
/// </devdoc>
[
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;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.INSERT_WIDTH_SIZE"]/*' />
/// <devdoc>
/// This is the arbitrary number of pixels that the Win32 control
/// inserts between calendars horizontally, regardless of font.
/// </devdoc>
/// <internalonly/>
private const int INSERT_WIDTH_SIZE = 6;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.INSERT_HEIGHT_SIZE"]/*' />
/// <devdoc>
/// This is the arbitrary number of pixels that the Win32 control
/// inserts between calendars vertically, regardless of font.
/// </devdoc>
/// <internalonly/>
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 int scaledExtraPadding = ExtraPadding;
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;
private NativeMethods.MONTCALENDAR_VIEW_MODE mcCurView = NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_MONTH;
private NativeMethods.MONTCALENDAR_VIEW_MODE mcOldView = NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_MONTH;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.monthsOfYear"]/*' />
/// <devdoc>
/// Bitmask for the annually bolded dates. Months start on January.
/// </devdoc>
/// <internalonly/>
private int[] monthsOfYear = new int[12];
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.datesToBoldMonthly"]/*' />
/// <devdoc>
/// Bitmask for the dates bolded monthly.
/// </devdoc>
/// <internalonly/>
private int datesToBoldMonthly = 0;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.arrayOfDates"]/*' />
/// <devdoc>
/// Lists are slow, so this section can be optimized.
/// Implementation is such that inserts are fast, removals are slow.
/// </devdoc>
/// <internalonly/>
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;
private int nativeWndProcCount = 0;
private static bool? restrictUnmanagedCode;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MonthCalendar"]/*' />
/// <devdoc>
/// Creates a new MonthCalendar object. Styles are the default for a
/// regular month calendar control.
/// </devdoc>
public MonthCalendar()
: base() {
PrepareForDrawing();
selectionStart = todayDate;
selectionEnd = todayDate;
SetStyle(ControlStyles.UserPaint, false);
SetStyle(ControlStyles.StandardClick, false);
TabStop = true;
if (!restrictUnmanagedCode.HasValue) {
bool demandUnmanagedFailed = false;
try {
IntSecurity.UnmanagedCode.Demand();
restrictUnmanagedCode = false;
}
catch {
// ensure that the static field is written to exactly once to avoid race conditions
demandUnmanagedFailed = true;
}
if (demandUnmanagedFailed) {
// Demand for unmanaged code failed, thus we are running in partial trust.
// We need to assert a registry access permission, this is safe because
// we are reading the registry and are not returning the information
// from the registry to the user.
new RegistryPermission(PermissionState.Unrestricted).Assert();
try {
// for 32 bit applications on 64 bit machines this code is reading
// HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node node
// to opt out, set a DWORD value AllowWindowsFormsReentrantDestroy=1
RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework");
if (key != null) {
object o = key.GetValue("AllowWindowsFormsReentrantDestroy");
if ((o != null) && (o is int) && ((int)o == 1)) {
restrictUnmanagedCode = false;
}
else {
restrictUnmanagedCode = true;
}
}
else {
restrictUnmanagedCode = true;
}
}
catch {
restrictUnmanagedCode = true;
}
finally {
System.Security.CodeAccessPermission.RevertAssert();
}
}
}
}
/// <summary>
/// MonthCalendar control accessbile object.
/// </summary>
/// <returns></returns>
protected override AccessibleObject CreateAccessibilityInstance() {
if (AccessibilityImprovements.Level1) {
return new MonthCalendarAccessibleObject(this);
}
else {
return base.CreateAccessibilityInstance();
}
}
protected override void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) {
base.RescaleConstantsForDpi(deviceDpiOld, deviceDpiNew);
PrepareForDrawing();
}
private void PrepareForDrawing() {
if (DpiHelper.EnableMonthCalendarHighDpiImprovements) {
scaledExtraPadding = LogicalToDeviceUnits(ExtraPadding);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.AnnuallyBoldedDates"]/*' />
/// <devdoc>
/// The array of DateTime objects that determines which annual days are shown
/// in bold.
/// </devdoc>
[
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<MONTHS_IN_YEAR; ++i)
monthsOfYear[i] = 0;
if (value != null && value.Length > 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();
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.BackColor"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRDescription(SR.MonthCalendarMonthBackColorDescr)]
public override Color BackColor {
get {
if (ShouldSerializeBackColor()) {
return base.BackColor;
}
else {
return SystemColors.Window;
}
}
set {
base.BackColor = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.BackgroundImage"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public override Image BackgroundImage {
get {
return base.BackgroundImage;
}
set {
base.BackgroundImage = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.BackgroundImageChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler BackgroundImageChanged {
add {
base.BackgroundImageChanged += value;
}
remove {
base.BackgroundImageChanged -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.BackgroundImageLayout"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public override ImageLayout BackgroundImageLayout {
get {
return base.BackgroundImageLayout;
}
set {
base.BackgroundImageLayout = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.BackgroundImageLayoutChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler BackgroundImageLayoutChanged {
add {
base.BackgroundImageLayoutChanged += value;
}
remove {
base.BackgroundImageLayoutChanged -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.BoldedDates"]/*' />
/// <devdoc>
/// The array of DateTime objects that determines which non-recurring
/// specified dates are shown in bold.
/// </devdoc>
/*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();
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.CalendarDimensions"]/*' />
/// <devdoc>
/// The number of columns and rows of months that will be displayed
/// in the MonthCalendar control.
/// </devdoc>
[
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);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.CreateParams"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
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;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DefaultImeMode"]/*' />
protected override ImeMode DefaultImeMode {
get {
return ImeMode.Disable;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DefaultMargin"]/*' />
protected override Padding DefaultMargin {
get { return new Padding(9); }
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DefaultSize"]/*' />
protected override Size DefaultSize {
get {
return GetMinReqRect();
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DoubleBuffered"]/*' />
/// <devdoc>
/// This property is overridden and hidden from statement completion
/// on controls that are based on Win32 Native Controls.
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Never)]
protected override bool DoubleBuffered {
get {
return base.DoubleBuffered;
}
set {
base.DoubleBuffered = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.FirstDayOfWeek"]/*' />
/// <devdoc>
/// The first day of the week for the month calendar control.
/// </devdoc>
[
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);
}
}
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ForeColor"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRDescription(SR.MonthCalendarForeColorDescr)]
public override Color ForeColor {
get {
if (ShouldSerializeForeColor()) {
return base.ForeColor;
}
else {
return SystemColors.WindowText;
}
}
set {
base.ForeColor = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ImeMode"]/*' />
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public ImeMode ImeMode {
get {
return base.ImeMode;
}
set {
base.ImeMode = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ImeModeChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event EventHandler ImeModeChanged {
add {
base.ImeModeChanged += value;
}
remove {
base.ImeModeChanged -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MaxDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
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();
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MaxSelectionCount"]/*' />
/// <devdoc>
/// The maximum number of days that can be selected in a
/// month calendar control. This method does not affect the current
/// selection range.
/// </devdoc>
[
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 (unchecked( (int) (long)SendMessage(NativeMethods.MCM_SETMAXSELCOUNT, value, 0)) == 0)
throw new ArgumentException(SR.GetString(SR.MonthCalendarMaxSelCount, (value).ToString("D", CultureInfo.CurrentCulture)), "MaxSelectionCount");
}
maxSelectionCount = value;
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MinDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
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();
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MonthlyBoldedDates"]/*' />
/// <devdoc>
/// The array of DateTime objects that determine which monthly days to bold.
/// </devdoc>
[
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();
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.Now"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
private DateTime Now {
get {
return DateTime.Now.Date;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.Padding"]/*' />
/// <devdoc>
/// <para>
/// <para>[To be supplied.]</para>
/// </para>
/// </devdoc>
[
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; }
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RightToLeftLayout"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
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);
}
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ScrollChange"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
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;
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SelectionEnd"]/*' />
/// <devdoc>
/// <para>Indicates the end date of the selected range of dates.</para>
/// </devdoc>
[
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);
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SelectionStart"]/*' />
/// <devdoc>
/// <para>
/// Indicates
/// the start date of the selected range of dates.</para>
/// </devdoc>
[
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);
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SelectionRange"]/*' />
/// <devdoc>
/// Retrieves the selection range for a month calendar control.
/// </devdoc>
[
SRCategory(SR.CatBehavior),
SRDescription(SR.MonthCalendarSelectionRangeDescr),
Bindable(true)
]
public SelectionRange SelectionRange {
get {
return new SelectionRange(SelectionStart, SelectionEnd);
}
set {
SetSelectionRange(value.Start, value.End);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ShowToday"]/*' />
/// <devdoc>
/// Indicates whether the month calendar control will display
/// the "today" date at the bottom of the control.
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(true),
SRDescription(SR.MonthCalendarShowTodayDescr)
]
public bool ShowToday {
get {
return showToday;
}
set {
if (showToday != value) {
showToday = value;
UpdateStyles();
AdjustSize();
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ShowTodayCircle"]/*' />
/// <devdoc>
/// Indicates whether the month calendar control will circle
/// the "today" date.
/// </devdoc>
[
SRCategory(SR.CatBehavior),
DefaultValue(true),
SRDescription(SR.MonthCalendarShowTodayCircleDescr)
]
public bool ShowTodayCircle {
get {
return showTodayCircle;
}
set {
if (showTodayCircle != value) {
showTodayCircle = value;
UpdateStyles();
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ShowWeekNumbers"]/*' />
/// <devdoc>
/// Indicates whether the month calendar control will the display
/// week numbers (1-52) to the left of each row of days.
/// </devdoc>
[
SRCategory(SR.CatBehavior),
Localizable(true),
DefaultValue(false),
SRDescription(SR.MonthCalendarShowWeekNumbersDescr)
]
public bool ShowWeekNumbers {
get {
return showWeekNumbers;
}
set {
if (showWeekNumbers != value) {
showWeekNumbers = value;
UpdateStyles();
AdjustSize();
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SingleMonthSize"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
SRCategory(SR.CatAppearance),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.MonthCalendarSingleMonthSizeDescr)
]
public Size SingleMonthSize {
get {
NativeMethods.RECT rect = new NativeMethods.RECT();
if (IsHandleCreated) {
if (unchecked( (int) (long)SendMessage(NativeMethods.MCM_GETMINREQRECT, 0, ref rect)) == 0)
throw new InvalidOperationException(SR.GetString(SR.InvalidSingleMonthSize));
return new Size(rect.right, rect.bottom);
}
return DefaultSingleMonthSize;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.Size"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Localizable(false)
]
public new Size Size {
get {
return base.Size;
}
set {
base.Size = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.Text"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Bindable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
get {
return base.Text;
}
set {
base.Text = value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.TextChanged"]/*' />
/// <internalonly/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
new public event EventHandler TextChanged {
add {
base.TextChanged += value;
}
remove {
base.TextChanged -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.TodayDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
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();
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.TodayDateSet"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
[
SRCategory(SR.CatBehavior),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.MonthCalendarTodayDateSetDescr)
]
public bool TodayDateSet {
get {
return todayDateSet;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.TitleBackColor"]/*' />
/// <devdoc>
/// The background color displayed in the month calendar's
/// title.
/// </devdoc>
[
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);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.TitleForeColor"]/*' />
/// <devdoc>
/// The foreground color used to display text within the month
/// calendar's title.
/// </devdoc>
[
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);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.TrailingForeColor"]/*' />
/// <devdoc>
/// The color used to display the previous and following months that
/// appear on the current month calendar.
/// </devdoc>
[
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);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.AddAnnuallyBoldedDate"]/*' />
/// <devdoc>
/// Adds a day that will be bolded annually on the month calendar.
/// Be sure to call updateBoldedDates() afterwards.
/// </devdoc>
public void AddAnnuallyBoldedDate(DateTime date) {
annualArrayOfDates.Add(date);
monthsOfYear[date.Month-1] |= 0x00000001<<(date.Day-1);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.AddBoldedDate"]/*' />
/// <devdoc>
/// Adds a day that will be bolded on the month calendar.
/// Be sure to call updateBoldedDates() afterwards.
/// </devdoc>
public void AddBoldedDate(DateTime date) {
if (!this.arrayOfDates.Contains(date)) {
this.arrayOfDates.Add(date);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.AddMonthlyBoldedDate"]/*' />
/// <devdoc>
/// Adds a day that will be bolded monthly on the month calendar.
/// Be sure to call updateBoldedDates() afterwards.
/// </devdoc>
public void AddMonthlyBoldedDate(DateTime date) {
this.monthlyArrayOfDates.Add(date);
datesToBoldMonthly |= 0x00000001<<(date.Day-1);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.Click"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event EventHandler Click {
add {
base.Click += value;
}
remove {
base.Click -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DateChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatAction), SRDescription(SR.MonthCalendarOnDateChangedDescr)]
public event DateRangeEventHandler DateChanged {
add {
onDateChanged += value;
}
remove {
onDateChanged -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DateSelected"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatAction), SRDescription(SR.MonthCalendarOnDateSelectedDescr)]
public event DateRangeEventHandler DateSelected {
add {
onDateSelected += value;
}
remove {
onDateSelected -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DoubleClick"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event EventHandler DoubleClick {
add {
base.DoubleClick += value;
}
remove {
base.DoubleClick -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MouseClick"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event MouseEventHandler MouseClick {
add {
base.MouseClick += value;
}
remove {
base.MouseClick -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MouseDoubleClick"]/*' />
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event MouseEventHandler MouseDoubleClick {
add {
base.MouseDoubleClick += value;
}
remove {
base.MouseDoubleClick -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnPaint"]/*' />
/// <devdoc>
/// MonthCalendar Onpaint.
/// </devdoc>
/// <internalonly/><hideinheritance/>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new event PaintEventHandler Paint {
add {
base.Paint += value;
}
remove {
base.Paint -= value;
}
}
/// <include file='doc\Form.uex' path='docs/doc[@for="Form.RightToLeftLayoutChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[SRCategory(SR.CatPropertyChanged), SRDescription(SR.ControlOnRightToLeftLayoutChangedDescr)]
public event EventHandler RightToLeftLayoutChanged {
add {
onRightToLeftLayoutChanged += value;
}
remove {
onRightToLeftLayoutChanged -= value;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.AdjustSize"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
/// <internalonly/>
private void AdjustSize() {
Size minSize = GetMinReqRect();
Size = minSize;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.BoldDates"]/*' />
/// <devdoc>
/// Event handler that bolds dates indicated by arrayOfDates
/// </devdoc>
/// <internalonly/>
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<numDates; ++i) {
DateTime date = (DateTime) arrayOfDates[i];
if (DateTime.Compare(date, range.Start) >= 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<months; ++i, ++startMonth)
e.DaysToBold[i] |= monthsOfYear[startMonth % MONTHS_IN_YEAR] | datesToBoldMonthly;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.CompareDayAndMonth"]/*' />
/// <devdoc>
/// Compares only the day and month of each time.
/// </devdoc>
/// <internalonly/>
private bool CompareDayAndMonth(DateTime t1, DateTime t2) {
return(t1.Day == t2.Day && t1.Month == t2.Month);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.CreateHandle"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
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();
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.Dispose"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
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);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.GetDisplayRange"]/*' />
/// <devdoc>
/// Retrieves date information that represents the low and high limits of the
/// control's display.
/// </devdoc>
public SelectionRange GetDisplayRange(bool visible) {
if (visible)
return GetMonthRange(NativeMethods.GMR_VISIBLE);
else
return GetMonthRange(NativeMethods.GMR_DAYSTATE);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.GetHitArea"]/*' />
/// <devdoc>
/// Retrieves the enumeration value corresponding to the hit area.
/// </devdoc>
/// <internalonly/>
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;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.GetMinReqRect"]/*' />
/// <devdoc>
/// stub for getMinReqRect (int, boolean)
/// </devdoc>
/// <internalonly/>
private Size GetMinReqRect() {
return GetMinReqRect(0, false, false);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.GetMinReqRect1"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
/// <internalonly/>
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 - scaledExtraPadding) /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 = unchecked( (int) (long)SendMessage(NativeMethods.MCM_GETMAXTODAYWIDTH, 0, 0));
if (maxTodayWidth > minSize.Width) {
minSize.Width = maxTodayWidth;
}
}
// Fudge factor
//
minSize.Width += scaledExtraPadding;
minSize.Height += scaledExtraPadding;
return minSize;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.GetMonthRange"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
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;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.GetPreferredHeight"]/*' />
/// <devdoc>
/// Called by setBoundsCore. If updateRows is true, then the
/// number of rows will be updated according to height.
/// </devdoc>
/// <internalonly/>
private int GetPreferredHeight(int height, bool updateRows) {
Size preferredSize = GetMinReqRect(height, updateRows, false);
return preferredSize.Height;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.GetPreferredWidth"]/*' />
/// <devdoc>
/// Called by setBoundsCore. If updateCols is true, then the
/// number of columns will be updated according to width.
/// </devdoc>
/// <internalonly/>
private int GetPreferredWidth(int width, bool updateCols) {
Size preferredSize = GetMinReqRect(width, false, updateCols);
return preferredSize.Width;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTest"]/*' />
/// <devdoc>
/// Determines which portion of a month calendar control is at
/// at a given point on the screen.
/// </devdoc>
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);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTest1"]/*' />
/// <devdoc>
/// Determines which portion of a month calendar control is at
/// at a given point on the screen.
/// </devdoc>
public HitTestInfo HitTest(Point point) {
return HitTest(point.X, point.Y);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.IsInputKey"]/*' />
/// <devdoc>
/// Handling special input keys, such as pgup, pgdown, home, end, etc...
/// </devdoc>
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);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnHandleCreated"]/*' />
/// <devdoc>
/// Overrides Control.OnHandleCreated()
/// </devdoc>
/// <internalonly/>
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);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnHandleDestroyed"]/*' />
/// <devdoc>
/// Overrides Control.OnHandleDestroyed()
/// </devdoc>
/// <internalonly/>
protected override void OnHandleDestroyed(EventArgs e) {
SystemEvents.UserPreferenceChanged -= new UserPreferenceChangedEventHandler(this.MarshaledUserPreferenceChanged);
base.OnHandleDestroyed(e);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnDateChanged"]/*' />
/// <devdoc>
/// Fires the event indicating that the currently selected date
/// or range of dates has changed.
/// </devdoc>
protected virtual void OnDateChanged(DateRangeEventArgs drevent) {
if (onDateChanged != null) {
onDateChanged(this, drevent);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnDateSelected"]/*' />
/// <devdoc>
/// Fires the event indicating that the user has changed his\her selection.
/// </devdoc>
protected virtual void OnDateSelected(DateRangeEventArgs drevent) {
if (onDateSelected != null) {
onDateSelected(this, drevent);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnFontChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override void OnFontChanged(EventArgs e) {
base.OnFontChanged(e);
AdjustSize();
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnForeColorChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override void OnForeColorChanged(EventArgs e) {
base.OnForeColorChanged(e);
SetControlColor(NativeMethods.MCSC_TEXT, ForeColor);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.OnBackColorChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected override void OnBackColorChanged(EventArgs e) {
base.OnBackColorChanged(e);
SetControlColor(NativeMethods.MCSC_MONTHBK, BackColor);
}
/// <include file='doc\Form.uex' path='docs/doc[@for="Form.OnRightToLeftLayoutChanged"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void OnRightToLeftLayoutChanged(EventArgs e) {
if (GetAnyDisposingInHierarchy()) {
return;
}
if (RightToLeft == RightToLeft.Yes) {
RecreateHandle();
}
if (onRightToLeftLayoutChanged != null) {
onRightToLeftLayoutChanged(this, e);
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RemoveAllAnnuallyBoldedDates"]/*' />
/// <devdoc>
/// Removes all annually bolded days. Be sure to call updateBoldedDates() afterwards.
/// </devdoc>
public void RemoveAllAnnuallyBoldedDates() {
this.annualArrayOfDates.Clear();
for (int i=0; i<MONTHS_IN_YEAR; ++i)
monthsOfYear[i] = 0;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RemoveAllBoldedDates"]/*' />
/// <devdoc>
/// Removes all the bolded days. Be sure to call updateBoldedDates() afterwards.
/// </devdoc>
public void RemoveAllBoldedDates() {
this.arrayOfDates.Clear();
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RemoveAllMonthlyBoldedDates"]/*' />
/// <devdoc>
/// Removes all monthly bolded days. Be sure to call updateBoldedDates() afterwards.
/// </devdoc>
public void RemoveAllMonthlyBoldedDates() {
this.monthlyArrayOfDates.Clear();
datesToBoldMonthly = 0;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RemoveAnnuallyBoldedDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
public void RemoveAnnuallyBoldedDate(DateTime date) {
int length = annualArrayOfDates.Count;
int i=0;
for (; i<length; ++i) {
if (CompareDayAndMonth((DateTime) annualArrayOfDates[i], date)) {
annualArrayOfDates.RemoveAt(i);
break;
}
}
--length;
for (int j=i; j<length; ++j) {
if (CompareDayAndMonth((DateTime) annualArrayOfDates[j], date)) {
return;
}
}
monthsOfYear[date.Month-1] &= ~(0x00000001<<(date.Day-1));
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RemoveBoldedDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
public void RemoveBoldedDate(DateTime date) {
int length = arrayOfDates.Count;
for (int i=0; i<length; ++i) {
if (DateTime.Compare( ((DateTime)arrayOfDates[i]).Date, date.Date) == 0) {
arrayOfDates.RemoveAt(i);
Invalidate();
return;
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RemoveMonthlyBoldedDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
public void RemoveMonthlyBoldedDate(DateTime date) {
int length = monthlyArrayOfDates.Count;
int i=0;
for (; i<length; ++i) {
if (CompareDayAndMonth((DateTime) monthlyArrayOfDates[i], date)) {
monthlyArrayOfDates.RemoveAt(i);
break;
}
}
--length;
for (int j=i; j<length; ++j) {
if (CompareDayAndMonth((DateTime) monthlyArrayOfDates[j], date)) {
return;
}
}
datesToBoldMonthly &= ~(0x00000001<<(date.Day-1));
}
private void ResetAnnuallyBoldedDates() {
annualArrayOfDates.Clear();
}
private void ResetBoldedDates() {
arrayOfDates.Clear();
}
private void ResetCalendarDimensions() {
CalendarDimensions = new Size(1,1);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ResetMaxDate"]/*' />
/// <devdoc>
/// Resets the maximum selectable date. By default value, there is no
/// upper limit.
/// </devdoc>
private void ResetMaxDate() {
MaxDate = DateTime.MaxValue;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ResetMinDate"]/*' />
/// <devdoc>
/// Resets the minimum selectable date. By default value, there is no
/// lower limit.
/// </devdoc>
private void ResetMinDate() {
MinDate = DateTime.MinValue;
}
private void ResetMonthlyBoldedDates() {
monthlyArrayOfDates.Clear();
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ResetSelectionRange"]/*' />
/// <devdoc>
/// Resets the limits of the selection range. By default value, the upper
/// and lower limit is the current date.
/// </devdoc>
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;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ResetTodayDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
private void ResetTodayDate() {
todayDateSet = false;
UpdateTodayDate();
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.RequestBuffer"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
/// <internalonly/>
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;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SetBoundsCore"]/*' />
/// <devdoc>
/// Overrides Control.SetBoundsCore to enforce auto-sizing.
/// </devdoc>
/// <internalonly/>
protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
Rectangle oldBounds = Bounds;
Size max = SystemInformation.MaxWindowTrackSize;
// Second argument to GetPreferredWidth and GetPreferredHeight is a boolean specifying if we should update the number of rows/columns.
// We only want to update the number of rows/columns if we are not currently being scaled or if MonthCalendarHighDpiImprovements are off.
bool updateRowsAndColumns = !DpiHelper.EnableMonthCalendarHighDpiImprovements || !IsCurrentlyBeingScaled;
if (width != oldBounds.Width) {
if (width > max.Width)
width = max.Width;
width = GetPreferredWidth(width, updateRowsAndColumns);
}
if (height != oldBounds.Height) {
if (height > max.Height)
height = max.Height;
height = GetPreferredHeight(height, updateRowsAndColumns);
}
base.SetBoundsCore(x, y, width, height, specified);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SetControlColor"]/*' />
/// <devdoc>
/// If the handle has been created, this applies the color to the control
/// </devdoc>
/// <internalonly/>
private void SetControlColor(int colorIndex, Color value) {
if (IsHandleCreated) {
SendMessage(NativeMethods.MCM_SETCOLOR, colorIndex, ColorTranslator.ToWin32(value));
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SetRange"]/*' />
/// <devdoc>
/// Updates the window handle with the min/max ranges if it has been
/// created.
/// </devdoc>
/// <internalonly/>
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()));
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SetCalendarDimensions"]/*' />
/// <devdoc>
/// Sets the number of columns and rows to display.
/// </devdoc>
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();
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SetDate"]/*' />
/// <devdoc>
/// Sets date as the current selected date. The start and begin of
/// the selection range will both be equal to date.
/// </devdoc>
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);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SetSelectionRange"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
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);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.SetSelRange"]/*' />
/// <devdoc>
/// Upper must be greater than Lower
/// </devdoc>
/// <internalonly/>
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;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ShouldSerializeMaxDate"]/*' />
/// <devdoc>
/// Retrieves true if the maxDate should be persisted in code gen.
/// </devdoc>
private bool ShouldSerializeMaxDate() {
return maxDate != DateTimePicker.MaximumDateTime && maxDate != DateTime.MaxValue;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ShouldSerializeMinDate"]/*' />
/// <devdoc>
/// Retrieves true if the minDate should be persisted in code gen.
/// </devdoc>
private bool ShouldSerializeMinDate() {
return minDate != DateTimePicker.MinimumDateTime && minDate != DateTime.MinValue;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ShouldSerializeSelectionRange"]/*' />
/// <devdoc>
/// Retrieves true if the selectionRange should be persisted in code gen.
/// </devdoc>
private bool ShouldSerializeSelectionRange() {
return !DateTime.Equals(selectionEnd, selectionStart);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ShouldSerializeTodayDate"]/*' />
/// <devdoc>
/// Retrieves true if the todayDate should be persisted in code gen.
/// </devdoc>
private bool ShouldSerializeTodayDate() {
return todayDateSet;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.ToString"]/*' />
/// <devdoc>
/// Returns a string representation for this control.
/// </devdoc>
/// <internalonly/>
public override string ToString() {
string s = base.ToString();
return s + ", " + SelectionRange.ToString();
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.UpdateBoldedDates"]/*' />
/// <devdoc>
/// Forces month calendar to display the current set of bolded dates.
/// </devdoc>
public void UpdateBoldedDates() {
RecreateHandle();
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.UpdateTodayDate"]/*' />
/// <devdoc>
/// 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).
/// </devdoc>
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();
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.WmDateChanged"]/*' />
/// <devdoc>
/// Handles the MCN_SELCHANGE notification
/// </devdoc>
/// <internalonly/>
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);
if (AccessibilityImprovements.Level1) {
AccessibilityNotifyClients(AccessibleEvents.NameChange, -1);
AccessibilityNotifyClients(AccessibleEvents.ValueChange, -1);
}
//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));
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.WmDateBold"]/*' />
/// <devdoc>
/// Handles the MCN_GETDAYSTATE notification
/// </devdoc>
/// <internalonly/>
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);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.WmCalViewChanged"]/*' />
/// <devdoc>
/// Handles the MCN_VIEWCHANGE notification
/// </devdoc>
/// <internalonly/>
private void WmCalViewChanged (ref Message m) {
NativeMethods.NMVIEWCHANGE nmmcvm = (NativeMethods.NMVIEWCHANGE)m.GetLParam(typeof(NativeMethods.NMVIEWCHANGE));
Debug.Assert(mcCurView == (NativeMethods.MONTCALENDAR_VIEW_MODE)nmmcvm.uOldView, "Calendar view mode is out of sync with native control");
if (mcCurView != (NativeMethods.MONTCALENDAR_VIEW_MODE)nmmcvm.uNewView) {
mcOldView = mcCurView;
mcCurView = (NativeMethods.MONTCALENDAR_VIEW_MODE)nmmcvm.uNewView;
if (AccessibilityImprovements.Level1) {
AccessibilityNotifyClients(AccessibleEvents.ValueChange, -1);
AccessibilityNotifyClients(AccessibleEvents.NameChange, -1);
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.WmDateSelected"]/*' />
/// <devdoc>
/// Handles the MCN_SELECT notification
/// </devdoc>
/// <internalonly/>
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);
if (AccessibilityImprovements.Level1) {
AccessibilityNotifyClients(AccessibleEvents.NameChange, -1);
AccessibilityNotifyClients(AccessibleEvents.ValueChange, -1);
}
//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));
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.WmGetDlgCode"]/*' />
/// <devdoc>
/// Handles the WM_GETDLGCODE message
/// </devdoc>
/// <internalonly/>
private void WmGetDlgCode(ref Message m) {
// The MonthCalendar does its own handling of arrow keys
m.Result = (IntPtr)NativeMethods.DLGC_WANTARROWS;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.WmReflectCommand"]/*' />
/// <devdoc>
/// Handles the WM_COMMAND messages reflected from the parent control.
/// </devdoc>
/// <internalonly/>
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;
case NativeMethods.MCN_VIEWCHANGE:
if (AccessibilityImprovements.Level1) {
WmCalViewChanged(ref m);
}
break;
}
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.WndProc"]/*' />
/// <devdoc>
/// Overrided wndProc
/// </devdoc>
/// <internalonly/>
[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;
case NativeMethods.WM_DESTROY:
if (restrictUnmanagedCode == true && nativeWndProcCount > 0) {
throw new InvalidOperationException();
}
base.WndProc(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.DefWndProc"]/*' />
/// <internalonly/>
/// <devdoc>
/// Calls the default window procedure for the MonthCalendar control.
/// </devdoc>
[
SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode),
EditorBrowsable(EditorBrowsableState.Advanced)
]
protected override void DefWndProc(ref Message m) {
if (restrictUnmanagedCode == true) {
nativeWndProcCount++;
try {
base.DefWndProc(ref m);
}
finally {
nativeWndProcCount--;
}
return;
}
base.DefWndProc(ref m);
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTestInfo"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
public sealed class HitTestInfo {
readonly Point point;
readonly HitArea hitArea;
readonly DateTime time;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTestInfo.HitTestInfo"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
internal HitTestInfo(Point pt, HitArea area, DateTime time) {
this.point = pt;
this.hitArea = area;
this.time = time;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTestInfo.HitTestInfo1"]/*' />
/// <devdoc>
/// This constructor is used when the DateTime member is invalid.
/// </devdoc>
/// <internalonly/>
internal HitTestInfo(Point pt, HitArea area) {
this.point = pt;
this.hitArea = area;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTestInfo.Point"]/*' />
/// <devdoc>
/// The point that was hit-tested
/// </devdoc>
public Point Point {
get { return point; }
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTestInfo.HitArea"]/*' />
/// <devdoc>
/// Output member that receives an enumeration value from System.Windows.Forms.MonthCalendar.HitArea
/// representing the result of the hit-test operation.
/// </devdoc>
public HitArea HitArea {
get { return hitArea; }
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTestInfo.Time"]/*' />
/// <devdoc>
/// The time information specific to the location that was hit-tested. This value
/// will only be valid at certain values of hitArea.
/// </devdoc>
public DateTime Time {
get { return time; }
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.HitTestInfo.HitAreaHasValidDateTime"]/*' />
/// <devdoc>
/// Determines whether a given HitArea should have a corresponding valid DateTime
/// </devdoc>
/// <internalonly/>
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;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
public enum HitArea {
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.Nowhere"]/*' />
/// <devdoc>
/// The given point was not on the month calendar control, or it was in an inactive portion of the control.
/// </devdoc>
Nowhere = 0,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.TitleBackground"]/*' />
/// <devdoc>
/// The given point was over the background of a month's title
/// </devdoc>
TitleBackground = 1,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.TitleMonth"]/*' />
/// <devdoc>
/// The given point was in a month's title bar, over a month name
/// </devdoc>
TitleMonth = 2,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.TitleYear"]/*' />
/// <devdoc>
/// The given point was in a month's title bar, over the year value
/// </devdoc>
TitleYear = 3,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.NextMonthButton"]/*' />
/// <devdoc>
/// 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
/// </devdoc>
NextMonthButton = 4,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.PrevMonthButton"]/*' />
/// <devdoc>
/// 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
/// </devdoc>
PrevMonthButton = 5,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.CalendarBackground"]/*' />
/// <devdoc>
/// The given point was in the calendar's background
/// </devdoc>
CalendarBackground = 6,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.Date"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
Date = 7,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.NextMonthDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
NextMonthDate = 8,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.PrevMonthDate"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
PrevMonthDate = 9,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.DayOfWeek"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
DayOfWeek = 10,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.WeekNumbers"]/*' />
/// <devdoc>
/// 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.
/// </devdoc>
WeekNumbers = 11,
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="HitArea.TodayLink"]/*' />
/// <devdoc>
/// The given point was on the "today" link at the bottom of the month calendar control
/// </devdoc>
TodayLink = 12,
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MonthCalendarAccessibleObject"]/*' />
/// <internalonly/>
/// <devdoc>
/// </devdoc>
[System.Runtime.InteropServices.ComVisible(true)]
internal class MonthCalendarAccessibleObject : ControlAccessibleObject {
private MonthCalendar calendar;
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.CheckBoxAccessibleObject.MonthCalendarAccessibleObject"]/*' />
public MonthCalendarAccessibleObject(Control owner)
: base(owner) {
calendar = owner as MonthCalendar;
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MonthCalendarAccessibleObject.Role"]/*' />
public override AccessibleRole Role {
get {
if (calendar != null) {
AccessibleRole role = calendar.AccessibleRole;
if (role != AccessibleRole.Default) {
return role;
}
}
return AccessibleRole.Table;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MonthCalendarAccessibleObject.Help"]/*' />
public override string Help {
get {
var help = base.Help;
if (help != null) {
return help;
}
else {
if (calendar != null) {
return calendar.GetType().Name + "(" + calendar.GetType().BaseType.Name + ")";
}
}
return string.Empty;
}
}
/// <include file='doc\MonthCalendar.uex' path='docs/doc[@for="MonthCalendar.MonthCalendarAccessibleObject.Name"]/*' />
public override string Name {
get {
string name = base.Name;
if (name != null) {
return name;
}
if (calendar != null) {
if (calendar.mcCurView == NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_MONTH) {
if (System.DateTime.Equals(calendar.SelectionStart.Date, calendar.SelectionEnd.Date)) {
name = SR.GetString(SR.MonthCalendarSingleDateSelected, calendar.SelectionStart.ToLongDateString());
}
else {
name = SR.GetString(SR.MonthCalendarRangeSelected, calendar.SelectionStart.ToLongDateString(), calendar.SelectionEnd.ToLongDateString());
}
}
else if (this.calendar.mcCurView == NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_YEAR) {
if (System.DateTime.Equals(this.calendar.SelectionStart.Month, this.calendar.SelectionEnd.Month)) {
name = SR.GetString(SR.MonthCalendarSingleDateSelected, calendar.SelectionStart.ToString("y"));
}
else {
name = SR.GetString(SR.MonthCalendarRangeSelected, calendar.SelectionStart.ToString("y"), calendar.SelectionEnd.ToString("y"));
}
}
else if (calendar.mcCurView == NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_DECADE) {
if (System.DateTime.Equals(calendar.SelectionStart.Year, calendar.SelectionEnd.Year)) {
name = SR.GetString(SR.MonthCalendarSingleYearSelected, calendar.SelectionStart.ToString("yyyy"));
}
else {
name = SR.GetString(SR.MonthCalendarYearRangeSelected, calendar.SelectionStart.ToString("yyyy"), calendar.SelectionEnd.ToString("yyyy"));
}
}
else if (calendar.mcCurView == NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_CENTURY) {
name = SR.GetString(SR.MonthCalendarSingleDecadeSelected, calendar.SelectionStart.ToString("yyyy"));
}
}
return name;
}
}
public override string Value {
get {
var value = string.Empty;
try {
if (calendar != null) {
if (calendar.mcCurView == NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_MONTH) {
if (System.DateTime.Equals(calendar.SelectionStart.Date, calendar.SelectionEnd.Date)) {
value = calendar.SelectionStart.ToLongDateString();
}
else {
value = string.Format("{0} - {1}", calendar.SelectionStart.ToLongDateString(), calendar.SelectionEnd.ToLongDateString());
}
}
else if (this.calendar.mcCurView == NativeMethods.MONTCALENDAR_VIEW_MODE.MCMV_YEAR) {
if (System.DateTime.Equals(this.calendar.SelectionStart.Month, this.calendar.SelectionEnd.Month)) {
value = calendar.SelectionStart.ToString("y");
}
else {
value = string.Format("{0} - {1}", calendar.SelectionStart.ToString("y"), calendar.SelectionEnd.ToString("y"));
}
}
else {
value = string.Format("{0} - {1}", calendar.SelectionRange.Start.ToString(), calendar.SelectionRange.End.ToString());
}
}
}
catch {
value = base.Value;
}
return value;
}
set {
base.Value = value;
}
}
}
} // end class MonthCalendar
}
|