/// <summary> /// Initializes a new instance of the <see cref="MonthCalendarHitTest"/> class. /// </summary> /// <param name="date">The date of the hit test.</param> /// <param name="type">The result type of the hit test.</param> /// <param name="bounds">The bounds of the resulting element.</param> public MonthCalendarHitTest( DateTime date, MonthCalendarHitType type, Rectangle bounds) : this(date, type, bounds, Rectangle.Empty) { }
/// <summary> /// Initializes a new instance of the <see cref="MonthCalendarHitTest"/> class. /// </summary> /// <param name="date">The date of the hit test.</param> /// <param name="type">The result type of the hit test.</param> /// <param name="bounds">The bounds of the resulting element.</param> public MonthCalendarHitTest( DateTime date, MonthCalendarHitType type, Rectangle bounds) : this(date, type, bounds, Rectangle.Empty) { }
/// <summary> /// Initializes a new instance of the <see cref="MonthCalendarHitTest"/> class. /// </summary> /// <param name="date"> /// The date of the hit test. /// </param> /// <param name="type"> /// The result type of the hit test. /// </param> /// <param name="bounds"> /// The bounds of the resulting element. /// </param> /// <param name="invalidateBounds"> /// The bounds to invalidate. /// </param> public MonthCalendarHitTest(DateTime date, MonthCalendarHitType type, Rectangle bounds, Rectangle invalidateBounds) { this.Date = date; this.Type = type; this.Bounds = bounds; this._invalidateBounds = invalidateBounds; }
/// <summary> /// Initializes a new instance of the <see cref="MonthCalendarHitTest"/> class. /// </summary> /// <param name="date">The date of the hit test.</param> /// <param name="type">The result type of the hit test.</param> /// <param name="bounds">The bounds of the resulting element.</param> /// <param name="invalidateBounds">The bounds to invalidate.</param> public MonthCalendarHitTest( DateTime date, MonthCalendarHitType type, Rectangle bounds, Rectangle invalidateBounds) { this.Date = date; this.Type = type; this.Bounds = bounds; this.invalidateBounds = invalidateBounds; }
/// <summary> /// Initializes a new instance of the <see cref="MonthCalendar"/> class. /// </summary> public MonthCalendar() { SetStyle( ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true); // initialize menus this.InitializeComponent(); this.extendSelection = false; this.showFooter = true; this.showWeekHeader = true; this.mouseLocation = Point.Empty; this.yearSelected = DateTime.MinValue; this.monthSelected = DateTime.MinValue; this.selectionStart = DateTime.Today; this.selectionEnd = DateTime.Today; this.currentHitType = MonthCalendarHitType.None; this.boldedDates = new List<DateTime>(); this.boldDatesCollection = new BoldedDatesCollection(); this.boldDateCategoryCollection = new BoldedDateCategoryCollection(this); this.currentMoveBounds = Rectangle.Empty; this.mouseMoveFlags = new MonthCalendarMouseMoveFlags(); this.selectionRanges = new List<SelectionRange>(); this.daySelectionMode = MonthCalendarSelectionMode.Manual; this.nonWorkDays = CalendarDayOfWeek.Saturday | CalendarDayOfWeek.Sunday; this.culture = CultureInfo.CurrentUICulture; this.cultureCalendar = CultureInfo.CurrentUICulture.DateTimeFormat.Calendar; this.eraRanges = GetEraRanges(this.cultureCalendar); this.minDate = this.cultureCalendar.MinSupportedDateTime.Date < new DateTime(1900, 1, 1) ? new DateTime(1900, 1, 1) : this.cultureCalendar.MinSupportedDateTime.Date; this.maxDate = this.cultureCalendar.MaxSupportedDateTime.Date > new DateTime(9998, 12, 31) ? new DateTime(9998, 12, 31) : this.cultureCalendar.MaxSupportedDateTime.Date; this.formatProvider = new MonthCalendarFormatProvider(this.culture, null, this.culture.TextInfo.IsRightToLeft) { MonthCalendar = this }; this.renderer = new MonthCalendarRenderer(this); this.calendarDimensions = new Size(1, 1); this.headerFont = new Font("Segoe UI", 9f, FontStyle.Regular); this.footerFont = new Font("Arial", 9f, FontStyle.Bold); this.dayHeaderFont = new Font("Segoe UI", 8f, FontStyle.Regular); this.dayTextAlign = ContentAlignment.MiddleCenter; // update year menu this.UpdateYearMenu(DateTime.Today.Year); // set start date this.SetStartDate(new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1)); this.CalculateSize(true); }
/// <summary> /// Raises the <see cref="System.Windows.Forms.Control.MouseUp"/> event. /// </summary> /// <param name="e">A <see cref="MouseEventArgs"/> that contains the event data.</param> protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); // if left mouse button is pressed and selection process was started if (e.Button == MouseButtons.Left && this.selectionStarted) { this.selectionRanges.Add(new SelectionRange(this.SelectionRange.Start, this.SelectionRange.End)); // reset selection process this.selectionStarted = false; this.Refresh(); // raise selected event if necessary if (this.backupRange.Start != this.SelectionRange.Start || this.backupRange.End != this.SelectionRange.End) { // raise date this.RaiseDateSelected(); } } // reset current hit type this.currentHitType = MonthCalendarHitType.None; this.Capture = false; }
/// <summary> /// Raises the <see cref="System.Windows.Forms.Control.MouseDown"/> event. /// </summary> /// <param name="e">A <see cref="MouseEventArgs"/> that contains the event data.</param> protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); this.Focus(); this.Capture = true; // reset the selection range where selection started this.selectionStartRange = null; if (e.Button == MouseButtons.Left) { // perform hit test MonthCalendarHitTest hit = this.HitTest(e.Location); // set current bounds this.currentMoveBounds = hit.Bounds; // set current hit type this.currentHitType = hit.Type; switch (hit.Type) { case MonthCalendarHitType.Day: { // save old selection range SelectionRange oldRange = this.SelectionRange; if (!this.extendSelection || this.daySelectionMode != MonthCalendarSelectionMode.Manual) { // clear all selection ranges this.selectionRanges.Clear(); } switch (this.daySelectionMode) { case MonthCalendarSelectionMode.Day: { this.OnDateClicked(new DateEventArgs(hit.Date)); // only single days are selectable if (this.selectionStart != hit.Date) { this.SelectionStart = hit.Date; this.RaiseDateSelected(); } break; } case MonthCalendarSelectionMode.WorkWeek: { // only single work week is selectable // get first day of week DateTime firstDay = new MonthCalendarDate(this.CultureCalendar, hit.Date).GetFirstDayInWeek(this.formatProvider).Date; // get work days List<DayOfWeek> workDays = DateMethods.GetWorkDays(this.nonWorkDays); // reset selection start and end this.selectionEnd = DateTime.MinValue; this.selectionStart = DateTime.MinValue; // current range SelectionRange currentRange = null; // build selection ranges for work days for (int i = 0; i < 7; i++) { DateTime toAdd = firstDay.AddDays(i); if (workDays.Contains(toAdd.DayOfWeek)) { if (currentRange == null) { currentRange = new SelectionRange(DateTime.MinValue, DateTime.MinValue); } if (currentRange.Start == DateTime.MinValue) { currentRange.Start = toAdd; } else { currentRange.End = toAdd; } } else if (currentRange != null) { this.selectionRanges.Add(currentRange); currentRange = null; } } if (this.selectionRanges.Count >= 1) { // set first selection range this.SelectionRange = this.selectionRanges[0]; this.selectionRanges.RemoveAt(0); // if selection range changed, raise event if (this.SelectionRange != oldRange) { this.RaiseDateSelected(); } } else { this.Refresh(); } break; } case MonthCalendarSelectionMode.FullWeek: { // only a full week is selectable // get selection start and end MonthCalendarDate dt = new MonthCalendarDate(this.CultureCalendar, hit.Date).GetFirstDayInWeek( this.formatProvider); this.selectionStart = dt.Date; this.selectionEnd = dt.GetEndDateOfWeek(this.formatProvider).Date; // if range changed, raise event if (this.SelectionRange != oldRange) { this.RaiseDateSelected(); this.Refresh(); } break; } case MonthCalendarSelectionMode.Month: { // only a full month is selectable MonthCalendarDate dt = new MonthCalendarDate(this.CultureCalendar, hit.Date).FirstOfMonth; // get selection start and end this.selectionStart = dt.Date; this.selectionEnd = dt.AddMonths(1).AddDays(-1).Date; // if range changed, raise event if (this.SelectionRange != oldRange) { this.RaiseDateSelected(); this.Refresh(); } break; } case MonthCalendarSelectionMode.Manual: { if (this.extendSelection) { var range = this.selectionRanges.Find(r => hit.Date >= r.Start && hit.Date <= r.End); if (range != null) { this.selectionRanges.Remove(range); } } // manual mode - selection ends when user is releasing the left mouse button this.selectionStarted = true; this.backupRange = this.SelectionRange; this.selectionEnd = DateTime.MinValue; this.SelectionStart = hit.Date; break; } } break; } case MonthCalendarHitType.Week: { this.selectionRanges.Clear(); if (this.maxSelectionCount > 6 || this.maxSelectionCount == 0) { this.backupRange = this.SelectionRange; this.selectionStarted = true; this.selectionEnd = new MonthCalendarDate(this.CultureCalendar, hit.Date).GetEndDateOfWeek(this.formatProvider).Date; this.SelectionStart = hit.Date; this.selectionStartRange = this.SelectionRange; } break; } case MonthCalendarHitType.MonthName: { this.monthSelected = hit.Date; this.mouseMoveFlags.HeaderDate = hit.Date; this.Invalidate(hit.InvalidateBounds); this.Update(); this.monthMenu.Tag = hit.Date; this.UpdateMonthMenu(this.CultureCalendar.GetYear(hit.Date)); this.showingMenu = true; // show month menu this.monthMenu.Show(this, hit.Bounds.Right, e.Location.Y); break; } case MonthCalendarHitType.MonthYear: { this.yearSelected = hit.Date; this.mouseMoveFlags.HeaderDate = hit.Date; this.Invalidate(hit.InvalidateBounds); this.Update(); this.UpdateYearMenu(this.CultureCalendar.GetYear(hit.Date)); this.yearMenu.Tag = hit.Date; this.showingMenu = true; // show year menu this.yearMenu.Show(this, hit.Bounds.Right, e.Location.Y); break; } case MonthCalendarHitType.Arrow: { // an arrow was pressed // set new start date if (this.SetStartDate(hit.Date)) { // update months this.UpdateMonths(); // raise event this.RaiseDateChanged(); this.mouseMoveFlags.HeaderDate = this.leftArrowRect.Contains(e.Location) ? this.months[0].Date : this.months[this.calendarDimensions.Width - 1].Date; this.Refresh(); } break; } case MonthCalendarHitType.Footer: { // footer was pressed this.selectionRanges.Clear(); bool raiseDateChanged = false; SelectionRange range = this.SelectionRange; // determine if date changed event has to be raised if (DateTime.Today < this.months[0].FirstVisibleDate || DateTime.Today > this.lastVisibleDate) { // set new start date if (this.SetStartDate(DateTime.Today)) { // update months this.UpdateMonths(); raiseDateChanged = true; } else { break; } } // set new selection start and end values this.selectionStart = DateTime.Today; this.selectionEnd = DateTime.Today; this.SetSelectionRange(this.daySelectionMode); this.OnDateClicked(new DateEventArgs(DateTime.Today)); // raise events if necessary if (range != this.SelectionRange) { this.RaiseDateSelected(); } if (raiseDateChanged) { this.RaiseDateChanged(); } this.Refresh(); break; } case MonthCalendarHitType.Header: { // header was pressed this.Invalidate(hit.Bounds); this.Update(); break; } } } }