Search code examples
.netwinformsdatagridviewdatetimepickerdatagridviewcolumn

how to get DateTimePicker checkstate value of DataGridView?


I have a DataGridview in which there is a DataTimePickerColumn, and it's DateTimePickerCell contain checkstate. How do I get the checkstate value after editing the checkstate?


Solution

  • Create a control inheriting from DateTimePicker and handle the DTN_DATETIMECHANGE notification. Then handle your DataGridView's EditingControlShowing event to add a handler for your DateTimePicker's new CheckedChanged event, or even you can create your own DataGridViewColumn and Cell type with DateTimePickerEx as EditingControl:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.Diagnostics;
    
    public class DateTimePickerEx : DateTimePicker
    {
      private bool _checked;
      private const int WM_REFLECT = 0x2000;
      public event CheckedChangedEventHandler CheckedChanged;
      public delegate void CheckedChangedEventHandler(object sender, System.EventArgs e);
    
      public DateTimePickerEx()
      {
        this._checked = this.Checked;
      }
    
      private void WmDateTimeChange(ref Message m)
      {
        NMDATETIMECHANGE nmdatetimechange = m.GetLParam(typeof(NMDATETIMECHANGE));
    
        if (nmdatetimechange.dwFlags == GetDateTimeValues.GDT_NONE) {
          if (this.ShowCheckBox && !this.Checked) {
            this._checked = false;
            if (CheckedChanged != null) {
              CheckedChanged(this, EventArgs.Empty);
            }
          }
        } else {
          if (this.ShowCheckBox && this.Checked && !this._checked) {
            this._checked = true;
            if (CheckedChanged != null) {
              CheckedChanged(this, EventArgs.Empty);
            }
          }
    
          this.Value = SysTimeToDateTime(nmdatetimechange.st);
        }
    
        m.Result = IntPtr.Zero;
      }
    
      private bool WmReflectCommand(ref Message m)
      {
        if (m.HWnd == this.Handle) {
          long code = NMHDR.FromMessage(m).code;
    
          switch (code) {
            case FWEx.Win32API.DateTimePickerNotifications.DTN_DATETIMECHANGE:
              this.WmDateTimeChange(ref m);
              return true;
          }
    
          return false;
        }
      }
    
      [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
      protected override void WndProc(ref System.Windows.Forms.Message m)
      {
        if (m.Msg != 71 && m.Msg != 513) {
          switch ((WindowsMessages)m.Msg) {
            case WindowsMessages.WM_NOTIFY + WM_REFLECT:
              if (!this.WmReflectCommand(ref m)) {
                break;
              }
    
              return;
    
              break;
          }
        }
    
        base.WndProc(m);
      }
    
      private System.DateTime SysTimeToDateTime(SYSTEMTIME st)
      {
        return new System.DateTime(st.Year, st.Month, st.Day, st.Hour, st.Minute, st.Second);
      }
    
      /// <summary>
      /// This structure contains information about a change that has taken place in a date and time picker (DTP) control.
      /// This structure is used with the DTN_DATETIMECHANGE notification message.
      /// </summary>
      /// <remarks></remarks>
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
      public struct NMDATETIMECHANGE
      {
        /// <summary>
        /// NMHDR structure that contains information about the notification message.
        /// </summary>
        public NMHDR nmhdr;
        /// <summary>
        /// Specifies if the control was set to no date status (for DTS_SHOWNONE only).
        /// Also specifies whether the contents of the st member are valid and contain current time information.
        /// </summary>
        public GetDateTimeValues dwFlags;
        /// <summary>
        /// SYSTEMTIME structure that contains information about the current system date and time. 
        /// </summary>
        public SYSTEMTIME st;
      }
    
      /// <summary>
      /// This structure contains information about a message.
      /// The pointer to this structure is specified as the lParam member of the WM_NOTIFY message.
      /// </summary>
      [StructLayout(LayoutKind.Sequential)]
      public struct NMHDR
      {
        /// <summary>
        /// Window handle to the control sending a message.
        /// </summary>
    
        public IntPtr hwndFrom;
        /// <summary>
        /// Identifier of the control sending a message.
        /// </summary>
    
        public IntPtr idFrom;
        /// <summary>
        /// Notification code. This member can be a control-specific notification code or it can be one of the common notification codes. The following values are supported if you include mouse support in your device platform:
        /// - NM_RCLICK
        /// - NM_RDBCLICK
        /// </summary>
    
        public int code;
        public static NMHDR FromMessage(System.Windows.Forms.Message msg)
        {
          return (NMHDR)msg.GetLParam(typeof(NMHDR));
        }
      }
    
      /// <summary>
      /// Specifies a date and time, using individual members for the month, day, year, weekday, hour, minute, second, and millisecond. 
      /// The time is either in coordinated universal time (UTC) or local time, depending on the function that is being called.
      /// </summary>
      /// <remarks>
      /// It is not recommended that you add and subtract values from the SYSTEMTIME structure to obtain relative times.
      /// </remarks>
      public struct SYSTEMTIME
      {
        /// <summary>
        /// The year. The valid values for this member are 1601 through 30827.
        /// </summary>
        public short Year;
        /// <summary>
        /// The month.
        /// </summary>
        public short Month;
        /// <summary>
        /// The day of the week. Sunday = 0.
        /// </summary>
        public short DayOfWeek;
        /// <summary>
        /// The day of the month. The valid values for this member are 1 through 31.
        /// </summary>
        public short Day;
        /// <summary>
        /// The hour. The valid values for this member are 0 through 23.
        /// </summary>
        public short Hour;
        /// <summary>
        /// The minute. The valid values for this member are 0 through 59.
        /// </summary>
        public short Minute;
        /// <summary>
        /// The second. The valid values for this member are 0 through 59.
        /// </summary>
        public short Second;
        /// <summary>
        /// The millisecond. The valid values for this member are 0 through 999.
        /// </summary>
        public short Milliseconds;
      }
    
      public enum GetDateTimeValues
      {
        /// <summary>
        /// Error.
        /// </summary>
        GDT_ERROR = -1,
        /// <summary>
        /// The control is not set to the no date status.
        /// The st member contains the current date and time. 
        /// </summary>
        GDT_VALID = 0,
        /// <summary>
        /// The control is set to no date status. 
        /// The no date status applies only to controls that are set to the DTS_SHOWNONE style. 
        /// </summary>
        GDT_NONE = 1
      }
    
      public enum WindowsMessages
      {
        /// <summary>
        ///Sent by a common control to its parent window when an event has occurred or the control requires some information.
        /// </summary>
        WM_NOTIFY = 0x4e
      }
    
      public enum DateTimePickerNotifications
      {
        DTN_FIRST = -740,
        DTN_LAST = -745,
        DTN_FIRST2 = -753,
        DTN_LAST2 = -799,
        DTN_DATETIMECHANGE = DTN_FIRST2 - 6,
        DTN_USERSTRING = DTN_FIRST2 - 5,
        DTN_WMKEYDOWN = DTN_FIRST2 - 4,
        DTN_FORMAT = DTN_FIRST2 - 3,
        DTN_FORMATQUERY = DTN_FIRST2 - 2,
        DTN_DROPDOWN = DTN_FIRST2 - 1,
        DTN_CLOSEUP = DTN_FIRST2
      }
    }
    

    Handle the DateTimePickerEx.CheckedChanged on DataGridView.EditingControlShowing:

        private void dgv_EditingControlShowing(System.Object sender, System.Windows.Forms.DataGridViewEditingControlShowingEventArgs e)
        {
            switch (this.dgv.CurrentCellAddress.X) {
                  case 0: // your DateTimePickerEx column number
                        DateTimePickerEx dtp = e.Control as DateTimePickerEx;
    
                        if (dtp != null) {
                              dtp.CheckedChanged += (object sen, EventArgs ea) => {
                                        //TODO: Add your code here
                              };
                        }
    
                    break;
            }
        }