在文章 自定义日历控件环境VS2019+NET4.6.1 基础上迭代,纯代码方式实现
DateTimePicker.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Windows.Forms; namespace CustomControls.DateTimePicker { public class DateTimePicker : UserControl { TextBox[] lst; [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never), Browsable(false)] public int Year { set { lst[0].Text = value.ToString("d4"); } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never), Browsable(false)] public int Month { set { if (value < 1 || value > 12) { throw new ArgumentOutOfRangeException("月份范围是1至12."); } lst[1].Text = value.ToString("d2"); } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never), Browsable(false)] public int Day { set { DateTime dt = new DateTime(lst[0].Text.ToInt(1), lst[1].Text.ToInt(1), 1, 0, 0, 0); dt = dt.AddMonths(1).AddSeconds(-10); if (value < 1 || value > dt.Day) { throw new ArgumentOutOfRangeException("当前月份日期范围是1至" + dt.Day + "."); } lst[2].Text = value.ToString("d2"); } } int _Radius = 1; public int Radius { get { return _Radius; } set { if (value < 1) { throw new ArgumentOutOfRangeException(); } _Radius = value; this.Invalidate(); } } DateTime _value = DateTime.Now; public DateTime Value { get { _value = new DateTime(lst[0].Text.ToInt(2020), lst[1].Text.ToInt(1), lst[2].Text.ToInt(1), lst[3].Text.ToInt(1), lst[4].Text.ToInt(1), lst[5].Text.ToInt(1)); return _value; } set { Year = value.Year; Month = value.Month; Day = value.Day; lst[3].Text = value.Hour.ToString("00"); lst[4].Text = value.Minute.ToString("00"); lst[5].Text = value.Second.ToString("00"); _value = value; } } public DateTimePicker() { lst = new TextBox[6]; for (int i = 0; i < 6; i++) { lst[i] = new TextBox() { Name = "txt" + i, BorderStyle = BorderStyle.None, Margin = new Padding(0), ReadOnly = true, TextAlign = HorizontalAlignment.Center }; if (i < 3) { lst[i].MouseDown += txtYear_MouseDown; } lst[i].GotFocus += Text_GotFocus; lst[i].Click += Text_GotFocus; lst[i].KeyDown += Text_KeyDown; } this.Controls.AddRange(lst); Value = DateTime.Now; BackColor = MonthCalendarBackColor = Color.White; } Color _backColor = Color.White, _monthCalendarBackColor = Color.White; public override Color BackColor { get => _backColor; set { _backColor = base.BackColor = value; foreach (TextBox text in lst) { text.BackColor = BackColor; } } } public Color MonthCalendarBackColor { get => _monthCalendarBackColor; set => _monthCalendarBackColor = value; } private void Text_KeyDown(object sender, KeyEventArgs e) { if (!(sender is TextBox _TextBox)) { return; } e.SuppressKeyPress = false; string _txt = _TextBox.Text; if (e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9) { } else if (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9) { } else if ((Keys)e.KeyValue == Keys.Delete) { if (_TextBox.SelectionLength > 0) { _txt = _TextBox.Text.Substring(0, _TextBox.SelectionStart) + _TextBox.Text.Substring(_TextBox.SelectionStart + _TextBox.SelectionLength); } else if (_TextBox.SelectionStart >= 0) { int _index = _TextBox.Text.Length - _TextBox.SelectionStart - 1; if (_index >= 0) { _txt = _txt.Substring(0, _TextBox.SelectionStart) + _txt.Substring(_TextBox.SelectionStart + 1, _index); } } _TextBox.Text = _txt; _TextBox.SelectionStart = _txt.Length; return; } else if ((Keys)e.KeyValue == Keys.Back) { if (_TextBox.SelectionLength > 0) { _txt = _TextBox.Text.Substring(0, _TextBox.SelectionStart) + _TextBox.Text.Substring(_TextBox.SelectionStart + _TextBox.SelectionLength); } else if (_TextBox.SelectionStart >= 0) { int _index = _TextBox.SelectionStart - 1; _index = _index < 0 ? 0 : _index; _txt = _txt.Substring(0, _index) + _txt.Substring(_TextBox.SelectionStart); } _TextBox.Text = _txt; _TextBox.SelectionStart = _txt.Length; return; } else { return; } if (_TextBox.SelectionLength > 0) { _txt = _txt.Substring(0, _TextBox.SelectionStart) + KeyName(e.KeyCode) + _txt.Substring(_TextBox.SelectionStart + _TextBox.SelectedText.Length); } else { if (_TextBox.SelectionStart >= 0) { _txt = _txt.Substring(0, _TextBox.SelectionStart) + KeyName(e.KeyCode) + _txt.Substring(_TextBox.SelectionStart); } else { _txt = _txt.Substring(0, _TextBox.SelectionStart) + KeyName(e.KeyCode); } } if (e.KeyCode != Keys.Delete && e.KeyCode != Keys.Back) { switch (_TextBox.Name.Replace("txt", "")) { case "0": if (_txt.ToInt(0) < 1 || _txt.ToInt(0) > 9999) { return; } break; case "1": if (_txt.ToInt(0) < 1 || _txt.ToInt(0) > 12) { return; } break; case "2": DateTime dt = new DateTime(lst[0].Text.ToInt(1), lst[1].Text.ToInt(1), 1, 0, 0, 0); dt = dt.AddMonths(1).AddSeconds(-10); if (_txt.ToInt(0) < 1 || _txt.ToInt(0) > dt.Day) { return; } break; case "3": if (_txt.ToInt(0) < 1 || _txt.ToInt(0) > 23) { return; } break; case "4": case "5": if (_txt.ToInt(0) < 1 || _txt.ToInt(0) > 59) { return; } break; default: break; } } _TextBox.Text = _txt; _TextBox.SelectionStart = _txt.Length; } char KeyName(Keys keycode) { if (keycode >= Keys.NumPad0 && keycode <= Keys.NumPad9) { char cc; switch (keycode) { case Keys.NumPad0: case Keys.D0: cc = '0'; break; case Keys.NumPad1: case Keys.D1: cc = '1'; break; case Keys.NumPad2: case Keys.D2: cc = '2'; break; case Keys.NumPad3: case Keys.D3: cc = '3'; break; case Keys.NumPad4: case Keys.D4: cc = '4'; break; case Keys.NumPad5: case Keys.D5: cc = '5'; break; case Keys.NumPad6: case Keys.D6: cc = '6'; break; case Keys.NumPad7: case Keys.D7: cc = '7'; break; case Keys.NumPad8: case Keys.D8: cc = '8'; break; case Keys.NumPad9: case Keys.D9: cc = '9'; break; default: cc = ' '; break; } return cc; } else { return (char)keycode; } } protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); foreach (Control item in this.Controls) { item.Font = this.Font; } } private void Text_GotFocus(object sender, EventArgs e) { if (sender is TextBox _txt) { _txt.SelectAll(); } } /// <summary>选择面板是否已经打开</summary> bool _dropDownShow = false; MonthCalendar _skinMonthCalendar; ToolStripDropDown _dropDown; private void txtYear_MouseDown(object sender, MouseEventArgs e) { if (!_dropDownShow) { _dropDownShow = true; _skinMonthCalendar = new MonthCalendar(this); _dropDown = new ToolStripDropDown() { Padding = Padding.Empty, Margin = Padding.Empty }; _dropDown.Items.Add(new ToolStripControlHost(_skinMonthCalendar) { AutoSize = false, Padding = Padding.Empty, Margin = Padding.Empty }); _dropDown.Show(this, new Point(0, this.Height)); _dropDown.Closed += (s1, e1) => { _dropDownShow = false; }; } else { _dropDownShow = false; DropDownClose(); } } public void DropDownClose() { if (_dropDown != null) { if (!_dropDown.IsDisposed) { _dropDown.Close(); } } _skinMonthCalendar = null; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); base.OnPaintBackground(e); e.Graphics.SmoothingMode = SmoothingMode.HighQuality; e.Graphics.CompositingQuality = CompositingQuality.HighQuality; e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; #region 根据内容和字体计算控件大小和位置 this.Height = lst[0].ClientSize.Height * 2; int _locationY = (this.Height - lst[0].Height) / 2; _locationY = _locationY > 0 ? _locationY : 0; int widthHangxian = (int)e.Graphics.MeasureString("-", Font).Width; int widthMaohao = (int)e.Graphics.MeasureString(":", Font).Width; lst[0].Size = lst[0].PreferredSize; lst[1].Size = lst[1].PreferredSize; lst[2].Size = lst[2].PreferredSize; lst[3].Size = lst[3].PreferredSize; lst[4].Size = lst[4].PreferredSize; lst[5].Size = lst[5].PreferredSize; lst[0].Location = new Point(10, _locationY); lst[1].Location = new Point(lst[0].Right + widthHangxian, _locationY); lst[2].Location = new Point(lst[1].Right + widthHangxian, _locationY); lst[3].Location = new Point(lst[2].Right + 10, _locationY); lst[4].Location = new Point(lst[3].Right + widthMaohao, _locationY); lst[5].Location = new Point(lst[4].Right + widthMaohao, _locationY); this.Width = lst[5].Right + 10; #endregion Rectangle rect = new Rectangle(0, 0, this.Width, this.Height); var path = GetRoundedRectPath(rect, _Radius); this.Region = new Region(path); try { Graphics _Graphics = e.Graphics; { using (SolidBrush b = new SolidBrush(BackColor)) { _Graphics.FillPath(b, path); } SolidBrush _brush = new SolidBrush(lst[0].ForeColor); int _widthLeft = 0; //年和月之间的- _Graphics.DrawString("-", Font, _brush, new PointF(_widthLeft + lst[0].Bounds.Right, _locationY)); _Graphics.DrawString("-", Font, _brush, new PointF(_widthLeft + lst[1].Bounds.Right, _locationY)); //小时和分钟之间的: _Graphics.DrawString(":", Font, _brush, new PointF(_widthLeft + lst[3].Bounds.Right, _locationY)); _Graphics.DrawString(":", Font, _brush, new PointF(_widthLeft + lst[4].Bounds.Right, _locationY)); } } catch (Exception ex) { Console.WriteLine(ex); } } GraphicsPath GetRoundedRectPath(Rectangle rect, int radius) { if (radius <= 0) { radius = 1; } int diameter = radius; Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter)); GraphicsPath path = new GraphicsPath(); path.AddArc(arcRect, 180, 90); arcRect.X = rect.Right - diameter; path.AddArc(arcRect, 270, 90); arcRect.Y = rect.Bottom - diameter; path.AddArc(arcRect, 0, 90); arcRect.X = rect.Left; path.AddArc(arcRect, 90, 90); path.CloseFigure(); return path; } } }
MonthCalendar.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Windows.Forms; using System.IO; using System.ComponentModel; namespace CustomControls.DateTimePicker { [ToolboxItem(false)] public class MonthCalendar : UserControl { readonly string[] Weekday = new string[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" }; DateTime CurrentDate; DateTimePicker dateTimePicker; Label labPrevYear; Label labPrevMonth; Label labNextMonth; Label labNextYear; Label labCurrentDate; Label labSelectedDate; string prevYear = "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAYAAACALL/6AAAABGdBTUEAALGPC/xhBQAAAF9JREFUKFNjQAe2UVHutuHhr4C0GVQIqxgYDBLF9pGRvrYREQ8co6KMoUJYxeDAPjraFGSSQ2SkB1QIqxgKoK8mu4iI1yAPQ4WwiqEAh6goA7vw8EuOkZH2UCEksUh7AHi0U/vJvVWtAAAAAElFTkSuQmCC", prevMonth = "iVBORw0KGgoAAAANSUhEUgAAAAYAAAALCAYAAABcUvyWAAAABGdBTUEAALGPC/xhBQAAAF1JREFUKFNjQAe2UVFmdhERJVAuBIAEbcPDXzmFhytDhRCCQNodKoRD0DkyUhxDEARsIyLu2EdGZkG5CGAfEWEL0uEQGekBFUIA++hoU/IlgZ57jeEQEAC7MiIiAwAzQymHZBUrOQAAAABJRU5ErkJggg==", nextMonth = "iVBORw0KGgoAAAANSUhEUgAAAAYAAAAKCAYAAACXDi8zAAAABGdBTUEAALGPC/xhBQAAAEdJREFUGFdjsIuI2ADE6xwaGlgYkAFIgAaSoatWMduGhy+3jYhYBhWCAN+0NC6gxBG78PAZUCGKBUEAKLge6JK5UC4UMDAAALD7LxOFqPajAAAAAElFTkSuQmCC", nextYear = "iVBORw0KGgoAAAANSUhEUgAAAAwAAAALCAYAAABLcGxfAAAABGdBTUEAALGPC/xhBQAAAI5JREFUKFNjsI2MDLYPD89MS0tjZYACbGIowDYiYpZdePhBt9hYbqgQVjEUAFYQEXHINy2NCyqEVQwFAJ0xG2QqsgJsYigArCAi4jSGJjQxOAAJ2oaH/3OOjBSHCmEVAwOQBMh6kIlQIaxiYECS4tDCQk50CWxicAD0UDe6BDYxOABKToYy4QCbGAMDAwMAcAFVx/DrCbkAAAAASUVORK5CYII="; private MonthCalendar() { labPrevYear = new Label() { Image = ConvertBase64ToImage(prevYear), Location = new Point(5, 5), Size = new Size(13, 13) }; labPrevMonth = new Label() { Image = ConvertBase64ToImage(prevMonth), Location = new Point(23, 5), Size = new Size(13, 13) }; labNextMonth = new Label() { Image = ConvertBase64ToImage(nextMonth), Location = new Point(144, 5), Size = new Size(13, 13) }; labNextYear = new Label() { Image = ConvertBase64ToImage(nextYear), Location = new Point(162, 5), Size = new Size(13, 13) }; labCurrentDate = new Label() { Location = new Point(41, 5), Size = new Size(98, 13), TextAlign = ContentAlignment.MiddleCenter }; labSelectedDate = new Label() { Location = new Point(0, 162), Size = new Size(180, 18), TextAlign = ContentAlignment.MiddleCenter }; this.Controls.Add(labPrevYear); this.Controls.Add(labPrevMonth); this.Controls.Add(labNextMonth); this.Controls.Add(labNextYear); foreach (Control item in this.Controls) { if (item is Label) { item.Click += (sender, e) => { if (sender == labPrevYear) { CurrentDate = CurrentDate.AddYears(-1); } else if (sender == labPrevMonth) { CurrentDate = CurrentDate.AddMonths(-1); } else if (sender == labNextMonth) { CurrentDate = CurrentDate.AddMonths(+1); } else if (sender == labNextYear) { CurrentDate = CurrentDate.AddYears(+1); } ShowDate(CurrentDate.Year, CurrentDate.Month); }; item.MouseEnter += (sender, e) => { ((Label)sender).BackColor = Color.FromArgb(247, 248, 249); }; item.MouseLeave += (sender, e) => { ((Label)sender).BackColor = Color.Transparent; }; } } this.Controls.Add(labCurrentDate); this.Controls.Add(labSelectedDate); this.Size = new Size(180, 180); } public MonthCalendar(DateTimePicker dateTimePicker) : this() { this.dateTimePicker = dateTimePicker; this.Font = dateTimePicker.Font; this.CurrentDate = dateTimePicker.Value; this.BackColor = dateTimePicker.MonthCalendarBackColor; DateInit(); ShowDate(CurrentDate.Year, CurrentDate.Month); labSelectedDate.Text = Weekday[(int)DateTime.Today.DayOfWeek] + " , " + DateTime.Today.Year + "/" + DateTime.Today.Month + "/" + DateTime.Today.Day; } Image ConvertBase64ToImage(string base64String) { byte[] imageBytes = Convert.FromBase64String(base64String); using (MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length)) { ms.Write(imageBytes, 0, imageBytes.Length); return Image.FromStream(ms, true); } } private void DateInit() { #region 星期 //周标题数组 Label[] WeekScheme = new Label[7]; for (int i = 0; i <= 6; i++) { WeekScheme[i] = new Label() { Text = Weekday[i].Substring(1), Width = 20, Height = 16, Font = this.Font, Location = new Point(3 + i * 25, 25), ForeColor = Color.FromArgb(85, 85, 85) }; } WeekScheme[0].ForeColor = WeekScheme[6].ForeColor = Color.FromArgb(255, 128, 128); #endregion this.Controls.AddRange(WeekScheme); int DateNum = 0; Label[] DateDay = new Label[42]; for (int i = 0; i < 6; i++) { int y = 47 + i * 18; for (int j = 0; j < 7; j++) { DateDay[DateNum] = new Label { Name = "AutoLabDateDay" + DateNum.ToString(), Width = 23, Height = 14, Font = this.Font, Location = new Point(1 + j * 25, y), TextAlign = ContentAlignment.MiddleRight }; DateNum++; } } this.Controls.AddRange(DateDay); } private void ShowDate(int year, int month) { labCurrentDate.Text = year + "年" + month + "月"; // 1 2 3 4 5 6 7 8 9 10 11 12 int[] DataDayLen = new int[] { 31, 30, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; DataDayLen[1] = ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)) ? 29 : 28; DateTime MyDate = DateTime.Parse(year + "-" + month + "-" + 1); DateTime Today = DateTime.Today; int Day = (int)MyDate.DayOfWeek; for (int L = 0; L < 42; L++) { Label labDateDay = (Label)this.Controls["AutoLabDateDay" + L]; labDateDay.Text = ""; labDateDay.BackColor = Color.Transparent; //前一个月 if (Day != 0 && L < Day) { labDateDay.Text = (DataDayLen[MyDate.AddMonths(-1).Month - 1] - Day + L + 1).ToString(); labDateDay.ForeColor = Color.DarkGray; labDateDay.Tag = DateTime.Parse(MyDate.AddMonths(-1).Year + "-" + MyDate.AddMonths(-1).Month + "-" + (DataDayLen[MyDate.AddMonths(-1).Month - 1] - Day + L + 1).ToString()); } //当前月 else if (L >= Day && L < DataDayLen[MyDate.Month - 1] + Day) { labDateDay.Text = (L - Day + 1).ToString(); labDateDay.ForeColor = Color.FromArgb(85, 85, 85); int day = Convert.ToInt32(labDateDay.Text); labDateDay.Tag = DateTime.Parse(MyDate.Year + "-" + MyDate.Month + "-" + labDateDay.Text); } //下一个月 else if (L >= DataDayLen[MyDate.Month - 1] + Day) { labDateDay.Text = (L - DataDayLen[MyDate.Month - 1] - Day + 1).ToString(); labDateDay.ForeColor = Color.DarkGray; labDateDay.Tag = DateTime.Parse(MyDate.AddMonths(+1).Year + "-" + MyDate.AddMonths(+1).Month + "-" + (L - DataDayLen[MyDate.Month - 1] - Day + 1).ToString()); } labDateDay.MouseLeave += (sender, e) => { Label CuLabel = (Label)sender; CuLabel.BackColor = Color.Transparent; }; labDateDay.MouseClick += (sender, e) => { Label label = (Label)sender; if (dateTimePicker != null) { DateTime time = Convert.ToDateTime(label.Tag); dateTimePicker.Year = time.Year; dateTimePicker.Month = time.Month; dateTimePicker.Day = time.Day; dateTimePicker.DropDownClose(); } }; labDateDay.MouseEnter += (sender, e) => { Label label = (Label)sender; label.BackColor = Color.FromArgb(247, 248, 249); if (label.Tag != null) { DateTime time = Convert.ToDateTime(label.Tag); labSelectedDate.Text = Weekday[(int)time.DayOfWeek] + " , " + time.Year + "-" + time.Month + "-" + time.Day; } else { labSelectedDate.Text = Weekday[(int)DateTime.Today.DayOfWeek] + " , " + DateTime.Today.Year + "-" + DateTime.Today.Month + "-" + DateTime.Today.Day; } }; } } } }
文章评论