How can I display a DateTimePicker in a DataGridView?
You haven't missed any built-in option, but it is possible to subclass both the DataGridViewColumn
and DataGridViewCell
classes to host any control of your choosing.
This article on MSDN explains the process in more detail, and even includes some sample code:
How to: Host Controls in Windows Forms DataGridView Cells
You can also find a complete sample on Code Project: Generic DataGridView V2.0
One strategy would be:
- to paint a
DateTimePicker
on top of the selected cell when it receives focus - hydrate the dtp with the cell's values
- when the dtp's value changes, mirror it back into the cell's value
- and hide the dtp when the cell loses focus
Here's a way to handle grid events with the laid out strategy:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
// determine if click was on our date column
if (dataGridView1.Columns[e.ColumnIndex].DataPropertyName == nameof(User.BirthDate))
{
// initialize DateTimePicker
DateTimePicker dtp = new DateTimePicker();
dtp.Format = DateTimePickerFormat.Short;
dtp.Visible = true;
dtp.Value = DateTime.Parse(dataGridView1.CurrentCell.Value.ToString());
// set size and location
var rect = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
dtp.Size = new Size(rect.Width, rect.Height);
dtp.Location = new Point(rect.X, rect.Y);
// attach events
dtp.CloseUp += new EventHandler(dtp_CloseUp);
dtp.TextChanged += new EventHandler(dtp_OnTextChange);
dataGridView1.Controls.Add(dtp);
}
}
// on text change of dtp, assign back to cell
private void dtp_OnTextChange(object sender, EventArgs e)
{
dataGridView1.CurrentCell.Value = dtp.Text.ToString();
}
// on close of cell, hide dtp
void dtp_CloseUp(object sender, EventArgs e)
{
dtp.Visible = false;
}
And Here's a basic setup for a form that has a DataGridView added to it
private void Form1_Load(object sender, EventArgs e)
{
// add columns
var nameCol = new DataGridViewTextBoxColumn(){DataPropertyName = nameof(User.Name),HeaderText = "Name"};
var dateCol = new DataGridViewTextBoxColumn(){DataPropertyName = nameof(User.BirthDate),HeaderText = "Birthday"};
dataGridView1.Columns.AddRange(nameCol, dateCol);
// add data source
var users = new List<User>()
{
new User() {Name = "Briana", BirthDate = new DateTime(2019,10,10)},
new User() {Name = "Grace", BirthDate = new DateTime(2018,1,18)}
};
dataGridView1.DataSource = users;
}
private DateTimePicker dtp { get; set; }
private class User
{
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}
Note: This approach does not currently handle keyboard events when the dtp has focus and also does not handle resizing or repainting if the form moves around