82871


FormアプリのDataGridViewのセルにDateTimePickerを用いて日時の設定と解除をしたいため、以下のサイトを参考に実装しました。  
概ね動作するのですが、複数の行に一度日時を設定した後、チェックボックスからチェックを外して日時設定をクリアしようとした場合に日時がクリアできないときがあります。（どういう場合に解除されないのか明確な条件はわかっていませんが何度か設定、解除を繰り返していると必ず発生します。）  
<https://social.msdn.microsoft.com/Forums/ja-
JP/32414a77-6a57-4969-ab3a-f7c4563e8118/datagridview-12398124751252312395-datetimepicker?forum=netfxgeneralja>

.NET Framework は4.7.2です。

参考ソースは以下になります、何か情報をお持ちでしたらご教示いただきたいです。  
1.Form画面でDataGridViewにDateTimePickerの列を設定する部分のソース

[code]

            private void Form1_Load(object sender, EventArgs e)
            {
                // 自作のCalendarColumnをDataGridViewに設定
                CalendarColumn col = new CalendarColumn();
                this.dataGridView2.Columns.Add(col);
                // yyyy/MM/dd HH:mm:ssの形式が表示できるように幅を広めに設定
                this.dataGridView2.Columns[0].Width = 200;
            }
    
[/code]

2.CalendarColumnクラスのソース (namespaceは任意です。)

[code]

    using System;
    using System.Windows.Forms;
    
    namespace DataGriViewDateTimePickerSample
    {
        public class CalendarColumn : DataGridViewColumn
        {
            public CalendarColumn() : base(new CalendarCell())
            {
            }
    
            public override DataGridViewCell CellTemplate
            {
                get
                {
                    return base.CellTemplate;
                }
                set
                {
                    // Ensure that the cell used for the template is a CalendarCell.
                    if (value != null &&
                        !value.GetType().IsAssignableFrom(typeof(CalendarCell)))
                    {
                        throw new InvalidCastException("Must be a CalendarCell");
                    }
                    base.CellTemplate = value;
                }
            }
        }
    }
    
    
[/code]

3.CalendarCellクラスのソース(namespaceは任意です。)

[code]

    using System;
    using System.Windows.Forms;
    
    namespace DataGriViewDateTimePickerSample
    {
        public class CalendarCell : DataGridViewTextBoxCell
        {
            public CalendarCell()
           : base()
            {
                this.Style.Format = "yyyy/MM/dd HH:mm:ss";
            }
    
            public override void InitializeEditingControl(int rowIndex, object
                initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
            {
                base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
                CalendarEditingControl ctl = DataGridView.EditingControl as CalendarEditingControl;
                if (this.Value == null || Value.ToString() == "")
                {
                    //Nullもしくは空白なら今日を表示値にしてチェックボックスを外す
                    ctl.Value = DateTime.Now;
                    ctl.Checked = false;
                }
                else
                {
                    ctl.Value = (DateTime)this.Value;
                    ctl.Checked = true;
                }
            }
    
            public override Type EditType 
            { 
                get { return typeof(CalendarEditingControl); } 
            }
    
            public override Type ValueType
            {
                get { return typeof(DateTime); }
            }
    
        }
    }
    
[/code]

4.CalendarEditingControlクラスのソース(namespaceは任意です。)

[code]

    using System;
    using System.Windows.Forms;
    
    namespace DataGriViewDateTimePickerSample
    {
        class CalendarEditingControl : DateTimePicker, IDataGridViewEditingControl
        {
            DataGridView dataGridView;
            private bool valueChanged = false;
            int rowIndex;
    
            public CalendarEditingControl()
            {
                this.Format = DateTimePickerFormat.Custom;
                this.CustomFormat = "yyyy/MM/dd HH:mm:ss";
                //チェックボックスを表示することでNULLを選択する場合
                this.ShowCheckBox = true;
            }
    
            public object EditingControlFormattedValue
            {
                get
                {
                    if (this.Checked)
                    {
                        this.CustomFormat = "yyyy/MM/dd HH:mm:ss";
                        return this.Value; //チェックを入れてたら日付あり
                    }
                    else
                    {
                        this.CustomFormat = " ";
                        return null;//チェックを外してたらnull
                    }
                }
                set
                {
                    if (value is DateTime)
                    {
                        this.Checked = true;//チェックをいれる
                        this.Value = DateTime.Now;
                    }
                    else if (value is String)
                    {
                        this.Checked = true;
                        try
                        {
                            this.Value = DateTime.Parse((String)value);
                        }
                        catch
                        {
                            this.Value = DateTime.Now;
                        }
                    }
                    else
                    {
                        this.Checked = false;//チェックボックスを外す
                        this.Value = DateTime.Now;
                    }
                }
            }
            public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
            {
                //nullは空白表示に
                DateTime? value = (DateTime?)this.EditingControlFormattedValue;
                if(value == null)
                {
                    return string.Empty;
                }
                else
                {
                    return value.Value.ToString(this.CustomFormat);
                }
            }
    
            public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
            {
                this.Font = dataGridViewCellStyle.Font;
                this.CalendarForeColor = dataGridViewCellStyle.ForeColor;
                this.CalendarMonthBackground = dataGridViewCellStyle.BackColor;
            }
    
            public int EditingControlRowIndex
            {
                get { return rowIndex; }
                set { rowIndex = value; }
            }
    
            public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
            {
                switch (key & Keys.KeyCode)
                {
                    case Keys.Left:
                    case Keys.Up:
                    case Keys.Down:
                    case Keys.Right:
                    case Keys.Home:
                    case Keys.End:
                    case Keys.PageDown:
                    case Keys.PageUp:
                        return true;
                    default:
                        return !dataGridViewWantsInputKey;
                }
            }
    
            public void PrepareEditingControlForEdit(bool selectAll)
            {
                // No preparation needs to be done.
            }
    
            public bool RepositionEditingControlOnValueChange { get { return false; } }
    
            public DataGridView EditingControlDataGridView
            {
                get { return dataGridView; }
                set { dataGridView = value; }
            }
    
            public bool EditingControlValueChanged
            {
                get { return valueChanged; }
                set { valueChanged = value; }
            }
    
            public Cursor EditingPanelCursor { get { return base.Cursor; } }
    
            protected override void OnValueChanged(EventArgs eventargs)
            {
                valueChanged = true;
                this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
                base.OnValueChanged(eventargs);
            }
        }
    }
    
[/code]

5.日時がクリアされない場合の挙動（クリアできるケースのほうが多いですが度々発生します。）  
上の例のようにチェックボックスのチェックを外した際に左側の列に鉛筆マークがでれば編集ありとして、セルはクリアされますが、チェックを外しても鉛筆マークが出ず、セルがクリアされない場合があります。  
[![不具合動作挙動](https://i.stack.imgur.com/SunDH.png)](https://i.stack.imgur.com/SunDH.png)


CC BY-SA 4.0
2021-09-26T10:06:23.423
82694
2021-10-04T09:32:11.427
2021-09-26T14:04:28.077
9228
9228
question
c# winforms
DataGridViewのセルにDateTimePicker(チェックボックス表示有り)を指定してチェックボックスを解除しても日時がクリアできない場合がある


自己解決したため、投稿します。  
DateTimePickerのValueChangedイベントでは、チェックボックスのチェック有無を検知できない場合があるため、DateTimePickerの別のイベント(MouseUpやKeyDown)でDateTimePickerのValueを変更するようにしたところ、意図した動作となりました。


CC BY-SA 4.0
2021-10-04T09:32:11.427
82871
2021-10-04T09:32:11.427
9228
82694
answer