I have this code to create and show a form with monthcalendar control on it.
private void showcalendar_Click(object sender, EventArgs e)
{
ShowCalendar();
}
void ShowCalendar()
{
DateTime current5 = DateTime.Now.AddDays(-5);
MonthCalendar cal = new MonthCalendar();
Panel panel = new Panel();
Form f = new Form();
cal.MaxSelectionCount = 1;
cal.SetDate(current5);
cal.DateSelected += new DateRangeEventHandler(DateSelected);
cal.ShowToday = true;
panel.Width = cal.Width;
panel.Height = cal.Height;
panel.BorderStyle = BorderStyle.FixedSingle;
panel.Controls.Add(cal);
f.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
f.ShowInTaskbar = false;
f.Size = panel.Size;
f.Location = MousePosition;
f.StartPosition = FormStartPosition.Manual;
f.Controls.Add(panel);
f.Deactivate += delegate { f.Close(); };
f.Show();
}
void DateSelected(object sender, DateRangeEventArgs e)
{
MonthCalendar cal = (MonthCalendar)sender;
Form f = cal.FindForm();
f.Close();
}
When I invoke ShowCalendar monthcalendar control is displayed and I can select date within it. The problem is that when I click on a certain area(the lowest one with current date depicted) I'm getting an exception - "Cannot access a disposed object. Object name: 'MonthCalendar'." I don't know how this exception arises at all and how to get rid of it. Maybe you have any thoughts?
My application is not multithreaded, just simple form with a button which invokes ShowCalendar function.
I have a quick solution in 3 steps.
Fixes and enhancements:
MonthCalendar
and MaskedTextBox
controls Steps:
1) Create a new windows forms application, view code in form1 and replace all text with this:
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) Add new class item into project and named clsMonthCalendarBehavior.cs
, later replace all text with this:
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) Run and test.
An interesting problem: the only way I could find to make it work is to keep the popup form as a property of the Main form and use Hide() instead of Close().
public partial class Form1 : Form
{
Form f = new Form();
public Form1()
{
InitializeComponent();
}
private void showcalendar_Click(object sender, EventArgs e)
{
ShowCalendar();
}
void ShowCalendar()
{
DateTime current5 = DateTime.Now.AddDays(-5);
MonthCalendar cal = new MonthCalendar();
Panel panel = new Panel();
cal.MaxSelectionCount = 1;
cal.SetDate(current5);
cal.DateSelected += new DateRangeEventHandler(DateSelected);
cal.ShowToday = true;
panel.Width = cal.Width;
panel.Height = cal.Height;
panel.BorderStyle = BorderStyle.FixedSingle;
panel.Controls.Add(cal);
f.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
f.ShowInTaskbar = false;
f.Size = panel.Size;
f.Location = MousePosition;
f.StartPosition = FormStartPosition.Manual;
f.Controls.Add(panel);
f.Deactivate += delegate { f.Hide(); };
f.Show();
}
void DateSelected(object sender, DateRangeEventArgs e)
{
DateTime selection = e.Start;
Console.WriteLine("Selected: {0}", selection.ToLongDateString());
this.Activate(); // Forces popup to de-activate
}
}
Workaround to this: remove MonthCalendar from it's parent before closing the form that hosts this MonthsCalendar. So the change is to add line cal.Parent.Controls.Remove(cal). The DateSelected method becomes:
void DateSelected(object sender, DateRangeEventArgs e)
{
MonthCalendar cal = (MonthCalendar)sender;
Form f = cal.FindForm();
cal.Parent.Controls.Remove(cal);
f.Close();
}
我认为问题在于您关闭了包含月历的表格,这使您的控件失效。
Interesting. I can reproduce this just fine here (running in VS 2008, target 3.5). There's quite a lot of noise in the code, the following causes the same behavior here, that is
ObjectDisposedException
Reduced/minimal complete test:
using System;
using System.Windows.Forms;
namespace Test
{
public class Form1 : Form
{
public Form1()
{
var dateSelectionButton = new Button();
SuspendLayout();
dateSelectionButton.Text = "Pick Date";
dateSelectionButton.Click += (SelectDateClick);
Controls.Add(dateSelectionButton);
ResumeLayout();
}
private void SelectDateClick(object sender, EventArgs e)
{
MonthCalendar cal = new MonthCalendar();
Form f = new Form();
cal.DateSelected += DateSelected;
f.Controls.Add(cal);
f.Show();
}
void DateSelected(object sender, DateRangeEventArgs e)
{
MonthCalendar cal = (MonthCalendar)sender;
Form f = cal.FindForm();
f.Close();
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.