using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace Wunnell.Windows.Forms { /// /// Represents a Windows control that allows the user to select a date /// and a time and to display the date and time with a specified format. /// /// /// The NullableDateTimePicker extends the DateTimePicker control by adding support for binding null /// values through the property. When a check box is displayed in the control and /// is not checked, the control is displayed blank instead of with greyed text. This represents a null value. /// [ToolboxBitmap(typeof(DateTimePicker))] public class NullableDateTimePicker : System.Windows.Forms.DateTimePicker { #region Constants /// /// The default value for the Format property. /// const DateTimePickerFormat DEFAULT_FORMAT = DateTimePickerFormat.Long; #endregion // Constants #region Variables /// /// The custom format string used to format the date and/or time in the control. /// private string _customFormat; /// /// Determines whether dates and times are displayed using standard or custom formatting. /// private DateTimePickerFormat _format; private object oldDataValue; #endregion // Variables #region Properties /// /// Gets or sets a value indicating whether the property has been /// set with a valid date/time value and the displayed value is able to be updated. /// /// /// true if the Value property has been set with a valid DateTime value and /// the displayed value is able to be updated; otherwise, false. The default is true. /// /// /// This property is used to obtain the state of the check box that is displayed if the /// property value is true. If the Checked property value is true, the /// control displays the properly formatted Value property value and the /// property value is the same as the Value property value; otherwise, if the ShowCheckBox /// property value is true, the control is blank and the DataValue property value is DBNull.Value. /// public new bool Checked { get { return base.Checked; } set { if (base.Checked != value) { base.Checked = value; this.SetBaseFormat(); } } } /// /// Gets or sets the custom date/time format string. /// /// /// A string that represents the custom date/time format. The default is a null reference (Nothing in Visual Basic). /// public new string CustomFormat { get { return this._customFormat; } set { if (value != this._customFormat) { this._customFormat = value; this.SetBaseFormat(); } } } /// /// Gets or sets the data value of the control. /// /// /// The date and time contained in the control if there is no checkbox displayed /// or the displayed check box is checked; otherwise, DBNull.Value. /// /// /// This property is intended to be bound to DataRow fields, allowing null values from databases to be /// entered and displayed. It accepts a null reference (Nothing in Visual Basic) or DBNull.Value /// to clear the date/time value contained in the control or a DateTime object to set it. /// [ Bindable(BindableSupport.Yes), Browsable(false) ] public object DataValue { get { if (base.Checked || !base.ShowCheckBox) { // Return the actual date and time when there is not an unchecked check box. return base.Value; } else { // Return a null database value when there is an unchecked check box. return DBNull.Value; } } set { if (value == null || value == DBNull.Value) { // Uncheck the control to indicate a null value. this.Checked = false; } else if (value is DateTime) { try { // Set the specified value. this.Value = (DateTime)value; } catch (Exception ex) { // Most likely the value assigned was outside the limits set by MinDate and MaxDate throw new ArgumentException(string.Format("'{0}' is an invalid value for 'DataValue'. See the inner exception for more information.", value.ToString()), ex); } // Explicitly check the control in case the specified value was the same as the current Value property. this.Checked = true; } else { // An invalid type of object was assigned. throw new ArgumentException(string.Format("'{0}' is an invalid type for 'DataValue'. 'DataValue' accepts only a null reference, DBNull.Value or a 'DateTime' object.", value.GetType().Name)); } } } /// /// Gets or sets the format of the date and time displayed in the control. /// /// /// One of the DateTimePickerFormat values. The default is Long. /// [DefaultValue(DEFAULT_FORMAT)] public new DateTimePickerFormat Format { get { return this._format; } set { if (value != this._format) { this._format = value; this.SetBaseFormat(); } } } /// /// Gets or sets a value indicating whether a check box is displayed to the left of the selected date. /// /// /// true if a check box is displayed to the left of the selected date; otherwise, false. The default is false. /// public new bool ShowCheckBox { get { return base.ShowCheckBox; } set { if (value != base.ShowCheckBox) { base.ShowCheckBox = value; this.SetBaseFormat(); } } } #endregion // Properties #region Constructors /// /// Initializes a new instance of the class. /// public NullableDateTimePicker() : base() { this._customFormat = base.CustomFormat; this._format = base.Format; } #endregion // Constructors #region Events /// /// Occurs when the property changes. /// /// /// This event is raised whenever the apparent value of the control changes. /// This may occur when the , or Value property changes. /// [ Category("Action"), Description("Occurs when the apparent value of the control changes.") ] public event EventHandler DataValueChanged; #endregion // Events #region Methods /// /// Raises the DataValueChanged event. /// /// /// An EventArgs that contains the event data. /// protected virtual void OnDataValueChanged(EventArgs e) { // Refresh the previous value. this.oldDataValue = this.DataValue; if (this.DataValueChanged != null) { // Raise the DataValueChanged event this.DataValueChanged(this, e); } } /// /// Raises the ValueChanged event. /// /// /// An EventArgs that contains the event data. /// protected override void OnValueChanged(EventArgs e) { this.SetBaseFormat(); base.OnValueChanged(e); } /// /// Sets the Format and CustomFormat base properties to either /// hide or display the date and/or time value contained in the control. /// private void SetBaseFormat() { string customFormat; DateTimePickerFormat format; if (base.Checked || !base.ShowCheckBox) { // Use the actual format values. customFormat = this._customFormat; format = this._format; } else { // Set the format to hide the text. customFormat = " "; format = DateTimePickerFormat.Custom; } if (base.CustomFormat != customFormat) { base.CustomFormat = customFormat; } if (base.Format != format) { base.Format = format; } bool dataValueChanged; if (this.oldDataValue is DateTime && this.DataValue is DateTime) { // Compare the old and current values as DateTime instances. dataValueChanged = ((DateTime)this.oldDataValue != (DateTime)this.DataValue); } else { // Compare the old and current values as Object instances. dataValueChanged = (this.oldDataValue != this.DataValue); } if (dataValueChanged) { this.OnDataValueChanged(EventArgs.Empty); } } #endregion // Methods } }