1

月間カレンダーを制御するフォームを作成して表示するためのこのコードがあります。

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();
}

ShowCalendarを呼び出すと、monthcalendarコントロールが表示され、その中で日付を選択できます。問題は、特定の領域(現在の日付が表示されている最も低い領域)をクリックすると、「破棄されたオブジェクトにアクセスできません。オブジェクト名:「MonthCalendar」」という例外が発生することです。この例外がどのように発生するのか、そしてそれを取り除く方法はわかりません。多分あなたは何か考えがありますか?

私のアプリケーションはマルチスレッドではなく、ShowCalendar関数を呼び出すボタンを備えた単純なフォームです。

エリアが選択されたカレンダー

4

5 に答える 5

1

興味深い問題:それを機能させるために私が見つけることができる唯一の方法は、ポップアップフォームをメインフォームのプロパティとして保持し、Close()の代わりにHide()を使用することです。

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
        }

    }
于 2011-05-12T12:52:21.697 に答える
1

3つのステップで簡単に解決できます。

修正と機能強化:

  • さまざまなバージョンの Windows で四角形の動的サイズが修正されました。
  • プリンシパル フォームが最上位かどうかを検証します。
  • バグなしでメモリからカレンダー フォームをアンロードします。
  • MonthCalendarMaskedTextBoxコントロール間の良好な動作

手順:

1) 新しい Windows フォーム アプリケーションを作成し、form1 のコードを表示して、すべてのテキストを次のように置き換えます。

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) 実行してテストします。

于 2012-05-09T19:51:40.833 に答える
1

これに対する回避策: この MonthsCalendar をホストするフォームを閉じる前に、その親から MonthCalendar を削除します。したがって、変更は cal.Parent.Controls.Remove(cal) 行を追加することです。DateSelected メソッドは次のようになります。

void DateSelected(object sender, DateRangeEventArgs e)
{
    MonthCalendar cal = (MonthCalendar)sender;
    Form f = cal.FindForm();
    cal.Parent.Controls.Remove(cal);
    f.Close();
}
于 2011-05-12T20:22:08.493 に答える
0

面白い。ここでこれをうまく再現できます(VS 2008、ターゲット3.5で実行)。コードにはかなりのノイズがあります。次の場合、ここで同じ動作が発生します。

  • 作品の曜日/番号をクリックして日付を選択する
  • 下部の「今日」の領域を選択すると、ObjectDisposedException

削減された/最小限の完全なテスト:

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();
        }
    }
}
于 2011-05-12T18:23:15.850 に答える
0

問題は、月のカレンダーが含まれているフォームを閉じて、コントロールを破棄することだと思います。

于 2011-05-12T11:51:53.047 に答える