我在3个步骤中迅速找到解决办法。
目标和增强:
- Rectangle dynamic size fixed under different versions of windows.
- Validate if principal form is topmost.
- Unload calendar form from memory without bug.
- Good behavior between
MonthCalendar
and MaskedTextBox
controls
步骤:
(1) 创建新的窗口申请表,以表格1看待代码,并以以下方式取代所有案文:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private System.Windows.Forms.CheckBox chkShowWeeksNumbers;
private System.Windows.Forms.CheckBox chkThisFormTopMost;
private System.Windows.Forms.MaskedTextBox maskedInputBox;
private System.Windows.Forms.Button btnShowFloatingCalendar;
public Form1()
{
this.chkShowWeeksNumbers = new System.Windows.Forms.CheckBox();
this.chkThisFormTopMost = new System.Windows.Forms.CheckBox();
this.maskedInputBox = new System.Windows.Forms.MaskedTextBox();
this.btnShowFloatingCalendar = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// chkShowNumbersOfWeeks
//
this.chkShowWeeksNumbers.AutoSize = true;
this.chkShowWeeksNumbers.Location = new System.Drawing.Point(18, 116);
this.chkShowWeeksNumbers.Name = "chkShowWeeksNumbers";
this.chkShowWeeksNumbers.Size = new System.Drawing.Size(137, 17);
this.chkShowWeeksNumbers.TabIndex = 1;
this.chkShowWeeksNumbers.Text = "Show number of weeks";
this.chkShowWeeksNumbers.UseVisualStyleBackColor = true;
//
// chkThisFormTopMost
//
this.chkThisFormTopMost.AutoSize = true;
this.chkThisFormTopMost.Location = new System.Drawing.Point(18, 139);
this.chkThisFormTopMost.Name = "chkThisFormTopMost";
this.chkThisFormTopMost.Size = new System.Drawing.Size(124, 17);
this.chkThisFormTopMost.TabIndex = 2;
this.chkThisFormTopMost.Text = "This form TopMost";
this.chkThisFormTopMost.UseVisualStyleBackColor = true;
this.chkThisFormTopMost.CheckedChanged += new EventHandler(chkThisFormTopMost_CheckedChanged);
//
// maskedInputBox
//
this.maskedInputBox.Location = new System.Drawing.Point(18, 53);
this.maskedInputBox.Mask = "00/00/0000 00:00";
this.maskedInputBox.Name = "maskedInputBox";
this.maskedInputBox.Size = new System.Drawing.Size(115, 20);
this.maskedInputBox.TabIndex = 3;
this.maskedInputBox.ValidatingType = typeof(System.DateTime);
//
// btnShowFloatingCalendar
//
this.btnShowFloatingCalendar.Location = new System.Drawing.Point(139, 49);
this.btnShowFloatingCalendar.Name = "btnShowFloatingCalendar";
this.btnShowFloatingCalendar.Size = new System.Drawing.Size(65, 27);
this.btnShowFloatingCalendar.TabIndex = 4;
this.btnShowFloatingCalendar.Text = "Calendar";
this.btnShowFloatingCalendar.UseVisualStyleBackColor = true;
this.btnShowFloatingCalendar.Click += new EventHandler(btnShowFloatingCalendar_Click);
//
// Form1
//
this.Controls.Add(this.btnShowFloatingCalendar);
this.Controls.Add(this.maskedInputBox);
this.Controls.Add(this.chkThisFormTopMost);
this.Controls.Add(this.chkShowWeeksNumbers);
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//DateTime format using in United States
//More info: http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28v=vs.71%29.aspx
// http://msdn.microsoft.com/en-us/library/5hh873ya.aspx
Thread.CurrentThread.CurrentCulture = new CultureInfo(0x0409);
CultureInfo cultureInfoUSA = new CultureInfo(0x0409, false);
this.maskedInputBox.Culture = cultureInfoUSA;
}
//Constructor
clsMonthCalendarBehavior userCalendar = new clsMonthCalendarBehavior();
private void btnShowFloatingCalendar_Click(object sender, EventArgs e)
{
userCalendar.ShowCalendar(this.maskedInputBox,
this.chkShowWeeksNumbers.Checked,
this.chkThisFormTopMost.Checked);
}
private void chkThisFormTopMost_CheckedChanged(object sender, EventArgs e)
{
this.TopMost = this.chkThisFormTopMost.Checked;
}
}
}
(2) 在项目中添加新的类别项目,并命名为<编码>clsMonthCalendarBehavior.cs,随后将所有案文改为:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace WindowsFormsApplication1
{
class clsMonthCalendarBehavior
{
private bool manualDateTimeIsDone
{
get
{
return (SetDateTimeManual(this._dateTimeInput.Text));
}
}
private static DateTime dateTimeManual;
//Determine if the user inserting a correctly date and time
internal static bool SetDateTimeManual(string inputReference)
{
DateTime newDateTime = new DateTime(2000, 1, 1, 0, 0, 0);
bool isDateTime = DateTime.TryParse(inputReference, out newDateTime);
if (isDateTime)
dateTimeManual = newDateTime;
return (isDateTime ? true : false);
}
private MaskedTextBox _dateTimeInput;
internal void ShowCalendar(MaskedTextBox dateTimeInput,
bool showNumbersOfWeeks,
bool principalFormIsTopMost)
{
MonthCalendar monthCalendarCustomized = new MonthCalendar();
Panel popupPanel = new Panel();
Form floatingForm = new Form();
this._dateTimeInput = dateTimeInput;
//OPTIONAL: Show week numbers
monthCalendarCustomized.ShowWeekNumbers = showNumbersOfWeeks;
monthCalendarCustomized.MaxSelectionCount = 1;
if (manualDateTimeIsDone)
monthCalendarCustomized.SetDate(dateTimeManual); //User, date and time selected
else
monthCalendarCustomized.SetDate(DateTime.Now); //System, actual date and time
monthCalendarCustomized.DateSelected += new DateRangeEventHandler(DateSelected);
monthCalendarCustomized.KeyDown +=new KeyEventHandler(KeyDown);
monthCalendarCustomized.ShowToday = true;
//IDEA: bolded dates about references, etc.
monthCalendarCustomized.BoldedDates = new DateTime[]
{
DateTime.Today.AddDays(1),
DateTime.Today.AddDays(2),
DateTime.Today.AddDays(7),
DateTime.Today.AddDays(31),
DateTime.Today.AddDays(10)
};
popupPanel.BorderStyle = BorderStyle.FixedSingle;
popupPanel.Controls.Add(monthCalendarCustomized);
floatingForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
floatingForm.ShowInTaskbar = false;
floatingForm.Location = Control.MousePosition;
floatingForm.StartPosition = FormStartPosition.Manual;
floatingForm.Controls.Add(popupPanel);
floatingForm.Deactivate += delegate { floatingForm.Close(); };
//NOTE: if principal from is topmost, cannot show in front "floatingForm" with calendar
// this option fix the situation.
floatingForm.TopMost = principalFormIsTopMost;
//NOTE: set initial size of controls.
floatingForm.Size = popupPanel.Size = new Size(20, 20);
floatingForm.Show();
popupPanel.Size = floatingForm.Size = monthCalendarCustomized.Size;
popupPanel.Width = popupPanel.Width + 2;
popupPanel.Height = popupPanel.Height + 2;
floatingForm.Width = floatingForm.Width + 3;
floatingForm.Height = floatingForm.Height + 3;
}
void DateSelected(object sender, DateRangeEventArgs e)
{
//Set data selected with culture info mask
this._dateTimeInput.Text = SetTimeValue(e.Start).ToString("MM/dd/yyyy HH:mm");
CloseFloatingForm(sender);
}
private static void CloseFloatingForm(object sender)
{
MonthCalendar monthCalendarCustomized = (MonthCalendar)sender;
Form floatingForm = monthCalendarCustomized.FindForm();
monthCalendarCustomized.Parent.Controls.Remove(monthCalendarCustomized);
floatingForm.Close();
}
private DateTime SetTimeValue(DateTime selectedDateTime)
{
//Recovery time of after selection, because when user select a new date
//Month Calendar reset the time
if (manualDateTimeIsDone)
{
TimeSpan addTimeValue = new TimeSpan(dateTimeManual.Hour,
dateTimeManual.Minute,
dateTimeManual.Second);
selectedDateTime = selectedDateTime.Add(addTimeValue);
}
return (selectedDateTime);
}
private void KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
CloseFloatingForm(sender);
}
}
}
3) 运行和测试。