Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I found a small problem in Mark Cranness's code above: On XP systems that have visual styles disabled entirely, Application.RenderWithVisualStyles is then set to False even when Application.EnableVisualStyles() is called. </p> <p>So the custom paint code does not run at all in that case. To fix it, I changed the first line of the FixVisualStylesMonthCalendar constructor to</p> <pre><code>if (Application.VisualStyleState != System.Windows.Forms.VisualStyles.VisualStyleState.NoneEnabled &amp;&amp; Environment.OSVersion.Version &lt; new Version(6, 0)) </code></pre> <p>Entire code is at the bottom of this answer.</p> <p>I could not find any way to comment on the answer itself. Credits for below code go to the original author - (If he or anyone can verify this answer and update it I would be happy to remove this one)</p> <pre><code>/// &lt;summary&gt; /// When Visual Styles are enabled on Windows XP, the MonthCalendar.SelectionRange /// does not paint correctly when more than one date is selected. /// See: http://msdn.microsoft.com/en-us/library/5d1acks5(VS.80).aspx /// "Additionally, if you enable visual styles on some controls, the control might display incorrectly /// in certain situations. These include the MonthCalendar control with a selection range set... /// This class fixes that problem. /// &lt;/summary&gt; /// &lt;remarks&gt;Author: Mark Cranness - PatronBase Limited.&lt;/remarks&gt; public class FixVisualStylesMonthCalendar : System.Windows.Forms.MonthCalendar { /// &lt;summary&gt; /// The width of a single cell (date) in the calendar. /// &lt;/summary&gt; private int dayCellWidth; /// &lt;summary&gt; /// The height of a single cell (date) in the calendar. /// &lt;/summary&gt; private int dayCellHeight; /// &lt;summary&gt; /// The calendar first day of the week actually used. /// &lt;/summary&gt; private DayOfWeek calendarFirstDayOfWeek; /// &lt;summary&gt; /// Only repaint when VisualStyles enabled on Windows XP. /// &lt;/summary&gt; private bool repaintSelectionRange = false; /// &lt;summary&gt; /// A MonthCalendar class that fixes SelectionRange painting problems /// on Windows XP when Visual Styles is enabled. /// &lt;/summary&gt; public FixVisualStylesMonthCalendar() { if (Application.VisualStyleState != System.Windows.Forms.VisualStyles.VisualStyleState.NoneEnabled &amp;&amp; //Application.RenderWithVisualStyles &amp;&amp; Environment.OSVersion.Version &lt; new Version(6, 0)) { // If Visual Styles are enabled, and XP, then fix-up the painting of SelectionRange this.repaintSelectionRange = true; this.OnSizeChanged(this, EventArgs.Empty); this.SizeChanged += new EventHandler(this.OnSizeChanged); } } /// &lt;summary&gt; /// The WM_PAINT message is sent to make a request to paint a portion of a window. /// &lt;/summary&gt; public const int WM_PAINT = 0x000F; /// &lt;summary&gt; /// Override WM_PAINT to repaint the selection range. /// &lt;/summary&gt; [System.Diagnostics.DebuggerStepThroughAttribute()] protected override void WndProc(ref Message m) { base.WndProc(ref m); if (m.Msg == WM_PAINT &amp;&amp; !this.DesignMode &amp;&amp; this.repaintSelectionRange) { // MonthCalendar is ControlStyles.UserPaint=false =&gt; Paint event is not raised this.RepaintSelectionRange(ref m); } } /// &lt;summary&gt; /// Repaint the SelectionRange. /// &lt;/summary&gt; private void RepaintSelectionRange(ref Message m) { using (Graphics graphics = this.CreateGraphics()) using (Brush backBrush = new SolidBrush(graphics.GetNearestColor(this.BackColor))) using (Brush selectionBrush = new SolidBrush(graphics.GetNearestColor(SystemColors.ActiveCaption))) { Rectangle todayFrame = Rectangle.Empty; // For each day in SelectionRange... for (DateTime selectionDate = this.SelectionStart; selectionDate &lt;= this.SelectionEnd; selectionDate = selectionDate.AddDays(1)) { Rectangle selectionDayRectangle = this.GetSelectionDayRectangle(selectionDate); if (selectionDayRectangle.IsEmpty) continue; if (selectionDate.Date == this.TodayDate) { todayFrame = selectionDayRectangle; } // Paint as 'selected' a little smaller than the whole rectangle Rectangle highlightRectangle = Rectangle.Inflate(selectionDayRectangle, 0, -2); if (selectionDate == this.SelectionStart) { highlightRectangle.X += 2; highlightRectangle.Width -= 2; } if (selectionDate == this.SelectionEnd) { highlightRectangle.Width -= 2; } // Paint background, selection and day-of-month text graphics.FillRectangle(backBrush, selectionDayRectangle); graphics.FillRectangle(selectionBrush, highlightRectangle); TextRenderer.DrawText( graphics, selectionDate.Day.ToString(), this.Font, selectionDayRectangle, SystemColors.ActiveCaptionText, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); } if (this.ShowTodayCircle &amp;&amp; !todayFrame.IsEmpty) { // Redraw the ShowTodayCircle (square) that we painted over above using (Pen redPen = new Pen(Color.Red)) { todayFrame.Width--; todayFrame.Height--; graphics.DrawRectangle(redPen, todayFrame); } } } } /// &lt;summary&gt; /// When displayed dates changed, clear the cached month locations. /// &lt;/summary&gt; private SelectionRange previousDisplayedDates = new SelectionRange(); /// &lt;summary&gt; /// Gets a graphics Rectangle for the area corresponding to a single date on the calendar. /// &lt;/summary&gt; private Rectangle GetSelectionDayRectangle(DateTime selectionDateTime) { // Handle the leading and trailing dates from the previous and next months SelectionRange allDisplayedDates = this.GetDisplayRange(false); SelectionRange fullMonthDates = this.GetDisplayRange(true); int adjust1Week; DateTime selectionDate = selectionDateTime.Date; if (selectionDate &lt; allDisplayedDates.Start || selectionDate &gt; allDisplayedDates.End) { // Selection Date is not displayed on calendar return Rectangle.Empty; } else if (selectionDate &lt; fullMonthDates.Start) { // Selection Date is trailing from the previous partial month selectionDate = selectionDate.AddDays(7); adjust1Week = -1; } else if (selectionDate &gt; fullMonthDates.End) { // Selection Date is leading from the next partial month selectionDate = selectionDate.AddDays(-14); adjust1Week = +2; } else { // A mainline date adjust1Week = 0; } // Discard cached month locations when calendar moves if (this.previousDisplayedDates.Start != allDisplayedDates.Start || this.previousDisplayedDates.End != allDisplayedDates.End) { this.DiscardCachedMonthDateAreaLocations(); this.previousDisplayedDates.Start = allDisplayedDates.Start; this.previousDisplayedDates.End = allDisplayedDates.End; } Point monthDateAreaLocation = this.GetMonthDateAreaLocation(selectionDate); if (monthDateAreaLocation.IsEmpty) return Rectangle.Empty; DayOfWeek monthFirstDayOfWeek = (new DateTime(selectionDate.Year, selectionDate.Month, 1)).DayOfWeek; int dayOfWeekAdjust = (int)monthFirstDayOfWeek - (int)this.calendarFirstDayOfWeek; if (dayOfWeekAdjust &lt; 0) dayOfWeekAdjust += 7; int row = (selectionDate.Day - 1 + dayOfWeekAdjust) / 7; int col = (selectionDate.Day - 1 + dayOfWeekAdjust) % 7; row += adjust1Week; return new Rectangle( monthDateAreaLocation.X + col * this.dayCellWidth, monthDateAreaLocation.Y + row * this.dayCellHeight, this.dayCellWidth, this.dayCellHeight); } /// &lt;summary&gt; /// Cached calendar location from the last lookup. /// &lt;/summary&gt; private Point[] cachedMonthDateAreaLocation = new Point[13]; /// &lt;summary&gt; /// Discard the cached month locations when calendar moves. /// &lt;/summary&gt; private void DiscardCachedMonthDateAreaLocations() { for (int i = 0; i &lt; 13; i++) this.cachedMonthDateAreaLocation[i] = Point.Empty; } /// &lt;summary&gt; /// Gets the graphics location (x,y point) of the top left of the /// calendar date area for the month containing the specified date. /// &lt;/summary&gt; private Point GetMonthDateAreaLocation(DateTime selectionDate) { Point monthDateAreaLocation = this.cachedMonthDateAreaLocation[selectionDate.Month]; HitTestInfo hitInfo; if (!monthDateAreaLocation.IsEmpty &amp;&amp; (hitInfo = this.HitTest(monthDateAreaLocation.X, monthDateAreaLocation.Y + this.dayCellHeight)) .HitArea == HitArea.Date &amp;&amp; hitInfo.Time.Year == selectionDate.Year &amp;&amp; hitInfo.Time.Month == selectionDate.Month) { // Use previously cached lookup return monthDateAreaLocation; } else { // Assume the worst (Error: empty) monthDateAreaLocation = this.cachedMonthDateAreaLocation[selectionDate.Month] = Point.Empty; Point monthDataAreaPoint = this.GetMonthDateAreaMiddle(selectionDate); if (monthDataAreaPoint.IsEmpty) return Point.Empty; // Move left from the middle to find the left edge of the Date area monthDateAreaLocation.X = monthDataAreaPoint.X--; HitTestInfo hitInfo1, hitInfo2; while ((hitInfo1 = this.HitTest(monthDataAreaPoint.X, monthDataAreaPoint.Y)) .HitArea == HitArea.Date &amp;&amp; hitInfo1.Time.Month == selectionDate.Month || (hitInfo2 = this.HitTest(monthDataAreaPoint.X, monthDataAreaPoint.Y + this.dayCellHeight)) .HitArea == HitArea.Date &amp;&amp; hitInfo2.Time.Month == selectionDate.Month) { monthDateAreaLocation.X = monthDataAreaPoint.X--; if (monthDateAreaLocation.X &lt; 0) return Point.Empty; // Error: bail } // Move up from the last column to find the top edge of the Date area int monthLastDayOfWeekX = monthDateAreaLocation.X + (this.dayCellWidth * 7 * 13) / 14; monthDateAreaLocation.Y = monthDataAreaPoint.Y--; while (this.HitTest(monthLastDayOfWeekX, monthDataAreaPoint.Y).HitArea == HitArea.Date) { monthDateAreaLocation.Y = monthDataAreaPoint.Y--; if (monthDateAreaLocation.Y &lt; 0) return Point.Empty; // Error: bail } // Got it this.cachedMonthDateAreaLocation[selectionDate.Month] = monthDateAreaLocation; return monthDateAreaLocation; } } /// &lt;summary&gt; /// Paranoid fudge/wobble of the GetMonthDateAreaMiddle in case /// our first estimate to hit the month misses. /// (Needed? perhaps not.) /// &lt;/summary&gt; private static Point[] searchSpiral = { new Point( 0, 0), new Point(-1,+1), new Point(+1,+1), new Point(+1,-1), new Point(-1,-1), new Point(-2,+2), new Point(+2,+2), new Point(+2,-2), new Point(-2,-2) }; /// &lt;summary&gt; /// Gets a point somewhere inside the calendar date area of /// the month containing the given selection date. /// &lt;/summary&gt; /// &lt;remarks&gt;The point returned will be HitArea.Date, and match the year and /// month of the selection date; otherwise it will be Point.Empty.&lt;/remarks&gt; private Point GetMonthDateAreaMiddle(DateTime selectionDate) { // Iterate over all displayed months, and a search spiral (needed? perhaps not) for (int dimX = 1; dimX &lt;= this.CalendarDimensions.Width; dimX++) { for (int dimY = 1; dimY &lt;= this.CalendarDimensions.Height; dimY++) { foreach (Point search in searchSpiral) { Point monthDateAreaMiddle = new Point( ((dimX - 1) * 2 + 1) * this.Width / (2 * this.CalendarDimensions.Width) + this.dayCellWidth * search.X, ((dimY - 1) * 2 + 1) * this.Height / (2 * this.CalendarDimensions.Height) + this.dayCellHeight * search.Y); HitTestInfo hitInfo = this.HitTest(monthDateAreaMiddle); if (hitInfo.HitArea == HitArea.Date) { // Got the Date Area of the month if (hitInfo.Time.Year == selectionDate.Year &amp;&amp; hitInfo.Time.Month == selectionDate.Month) { // For the correct month return monthDateAreaMiddle; } else { // Keep looking in the other months break; } } } } } return Point.Empty; // Error: not found } /// &lt;summary&gt; /// When this MonthCalendar is resized, recalculate the size of a day cell. /// &lt;/summary&gt; private void OnSizeChanged(object sender, EventArgs e) { // Discard previous cached Month Area Location DiscardCachedMonthDateAreaLocations(); this.dayCellWidth = this.dayCellHeight = 0; // Without this, the repaint sometimes does not happen... this.Invalidate(); // Determine Y offset of days area int middle = this.Width / (2 * this.CalendarDimensions.Width); int dateAreaTop = 0; while (this.HitTest(middle, dateAreaTop).HitArea != HitArea.PrevMonthDate &amp;&amp; this.HitTest(middle, dateAreaTop).HitArea != HitArea.Date) { dateAreaTop++; if (dateAreaTop &gt; this.ClientSize.Height) return; // Error: bail } // Determine height of a single day box int dayCellHeight = 1; DateTime dayCellTime = this.HitTest(middle, dateAreaTop).Time; while (this.HitTest(middle, dateAreaTop + dayCellHeight).Time == dayCellTime) { dayCellHeight++; } // Determine X offset of days area middle = this.Height / (2 * this.CalendarDimensions.Height); int dateAreaLeft = 0; while (this.HitTest(dateAreaLeft, middle).HitArea != HitArea.Date) { dateAreaLeft++; if (dateAreaLeft &gt; this.ClientSize.Width) return; // Error: bail } // Determine width of a single day box int dayCellWidth = 1; dayCellTime = this.HitTest(dateAreaLeft, middle).Time; while (this.HitTest(dateAreaLeft + dayCellWidth, middle).Time == dayCellTime) { dayCellWidth++; } // Record day box size and actual first day of the month used this.calendarFirstDayOfWeek = dayCellTime.DayOfWeek; this.dayCellWidth = dayCellWidth; this.dayCellHeight = dayCellHeight; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload