Problem in datagridview datetimepicker column.

Jul 24 2009 11:46 AM
I'm trying to make a datagridview column to act like a datetimepicker column (C#.Net 2005). These are the behaviours that the dgv should have:
1) Initially all the cells of the dtp column should be blank unless they are filled by the user.
2) As soon as the user enters a cell, the dtp control should appear as the editing control of that cell. If there's a value in the cell beforehand, that value is set as the value of the dtp editing control and it is checked, else the dtp editing control remains unchecked.
3) If the user selects a date from the dtp editing control and moves to another cell the value of the dtp should be set to the previous cell in string format (In that way we can define custom format for the cell e.g. dd MMM yyyy).
4) If the user unchecks the dtp editing control while it's on a cell the value of that cell should be set to null irrespective of whether the cell had a value beforehand.

I managed everything till point 3. But can't work out with point 4. Cannot set the value of a cell to null when its dtp editing control is unchecked. There's a way to do it by handling the Datagridview_CellValidating event. But in that case if the datagridview is data bound, u need to uncheck the editing control once, goto another cell, come back to the previous one and uncheck it once again to set its cell value to null. I want to know if there's any way to do it through the derived classes or their class template that I'm using so that I wont have to use that event and everything can be done through the class template only. Please help. My code follows:

Code for the template (I'm using a code file) containing all the derived classes:
 using System;
using System.Windows.Forms;

namespace DGV_DateTimePicker
{
public class DateTimePickerColumn : DataGridViewColumn
{
public DateTimePickerColumn()
: base(new DateTimePickerCell())
{
}

public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
// Ensure that the cell used for the template is a DateTimePickerCell.
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(DateTimePickerCell)))
{
throw new InvalidCastException("Must be a DateTimePickerCell");
}
base.CellTemplate = value;
}
}
}

public class DateTimePickerCell : DataGridViewTextBoxCell
{

public DateTimePickerCell()
: base()
{
// Use the custom defined date format.
this.Style.Format = "dd MMM yyyy";
}

public override void InitializeEditingControl(int rowIndex, object
initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
// Set the value of the editing control to the current cell value.
base.InitializeEditingControl(rowIndex, initialFormattedValue,
dataGridViewCellStyle);

DateTimePickerEditingControl ctl = (DateTimePickerEditingControl)DataGridView.EditingControl;
DateTime d;
ctl.Value = DateTime.TryParse((Value ?? "").ToString(), out d) ? d : DateTime.Now;

/*Check whether the datagridview is databound/unbound. In both cases if the value of the cell
isn't null then check the DateTimePickerEditing Control else uncheck it.*/
if (ctl.EditingControlDataGridView.CurrentCell.OwningColumn.IsDataBound)
ctl.Checked = Value.ToString() == "" ? false : Value == null ? false : true;
else
ctl.Checked = Value == null ? false : true;
}

public override Type EditType
{
get
{
// Return the type of the editing contol that DateTimePickerCell uses.
return typeof(DateTimePickerEditingControl);
}
}

public override Type ValueType
{
get
{
// Return the type of the value that DateTimePickerCell contains.
return typeof(DateTime);
}
}

public override object DefaultNewRowValue
{
get
{
//Return null as the default value for new row.
return null;
}
}
}

class DateTimePickerEditingControl : DateTimePicker, IDataGridViewEditingControl
{
DataGridView dataGridView;
private bool valueChanged = false;
int rowIndex;

public DateTimePickerEditingControl()
{
this.Format = DateTimePickerFormat.Custom;
this.CustomFormat = "dd MMM yyyy";
this.ShowCheckBox = true;
this.Checked = false;
}

// Implements the IDataGridViewEditingControl.EditingControlFormattedValue
// property.
public object EditingControlFormattedValue
{
get
{
return this.Value.ToShortDateString();
}
set
{
if (value is String)
{
this.Value = DateTime.Parse((String)value);
}
}
}

// Implements the
// IDataGridViewEditingControl.GetEditingControlFormattedValue method.
public object GetEditingControlFormattedValue(
DataGridViewDataErrorContexts context)
{
return EditingControlFormattedValue;
}

// Implements the
// IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
public void ApplyCellStyleToEditingControl(
DataGridViewCellStyle dataGridViewCellStyle)
{
this.Font = dataGridViewCellStyle.Font;
this.CalendarForeColor = dataGridViewCellStyle.ForeColor;
this.CalendarMonthBackground = dataGridViewCellStyle.BackColor;
}

// Implements the IDataGridViewEditingControl.EditingControlRowIndex
// property.
public int EditingControlRowIndex
{
get
{
return rowIndex;
}
set
{
rowIndex = value;
}
}

// Implements the IDataGridViewEditingControl.EditingControlWantsInputKey
// method.
public bool EditingControlWantsInputKey(
Keys key, bool dataGridViewWantsInputKey)
{
// Let the DateTimePicker handle the keys listed.
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;
}
}

// Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit
// method.
public void PrepareEditingControlForEdit(bool selectAll)
{
// No preparation needs to be done.
}

// Implements the IDataGridViewEditingControl
// .RepositionEditingControlOnValueChange property.
public bool RepositionEditingControlOnValueChange
{
get
{
return false;
}
}

// Implements the IDataGridViewEditingControl
// .EditingControlDataGridView property.
public DataGridView EditingControlDataGridView
{
get
{
return dataGridView;
}
set
{
dataGridView = value;
}
}

// Implements the IDataGridViewEditingControl
// .EditingControlValueChanged property.
public bool EditingControlValueChanged
{
get
{
return valueChanged;
}
set
{
valueChanged = value;
}
}

// Implements the IDataGridViewEditingControl
// .EditingPanelCursor property.
public Cursor EditingPanelCursor
{
get
{
return base.Cursor;
}
}

protected override void OnValueChanged(EventArgs eventargs)
{
// Notify the DataGridView that the contents of the cell
// have changed.
valueChanged = true;
this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
base.OnValueChanged(eventargs);
}
}
}


Code for the form containing the datagridview:
 private void Form1_Load(object sender, EventArgs e)
{
DateTimePickerColumn col = new DateTimePickerColumn();
dataGridView1.Columns.Add(col);
dataGridView1.RowCount = 5;
}


Reference from MSDN 2005- How to: Host Controls in Windows Forms DataGridView Cells