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
}
}