How can I display a DateTimePicker in a DataGridView?
Asked Answered
N

7

26

Is there any way to put a DateTimePicker control in the DataGridView?

I checked all the possible properties but it give option of checkbox, combo box etc, but not the DateTimePicker.

Nerveracking answered 27/1, 2011 at 11:22 Comment(0)
K
32

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

Kilderkin answered 27/1, 2011 at 11:39 Comment(0)
P
12

One strategy would be:

  1. to paint a DateTimePicker on top of the selected cell when it receives focus
  2. hydrate the dtp with the cell's values
  3. when the dtp's value changes, mirror it back into the cell's value
  4. 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

Photoreconnaissance answered 13/9, 2015 at 19:3 Comment(1)
This is a pretty large code block -- could you edit it to include some explanation of how it addresses the question?Touzle
L
8

Maybe this isn't proper, but easy trick and same result........ lot less code......I was just playing around and though outside the box, just set

I hide mine until they click cell, or you can show First I declared :

DateTimePicker1.Visible = False

when you click in cell, run this code...

    DateTimePicker1.Visible = True
    ActiveControl = DateTimePicker1

Then below

 Public Sub DateTimePicker1_ValueChanged(sender As System.Object, e As System.EventArgs) Handles DateTimePicker1.ValueChanged



    requestDGV.Rows(0).Cells("requestTimeOff").Value = (DateTimePicker1.Value)
    DateTimePicker1.Visible = False
    DateTimePicker1.Enabled = False

End Sub

Super Basic , and i have it sitting directly in the box, doesn't look out of place

Or super easy mode.......I just like to hide mine till column click

Public Sub DateTimePicker1_ValueChanged(sender As System.Object, e As System.EventArgs) Handles DateTimePicker1.ValueChanged


    requestDGV.Rows(0).Cells("requestTimeOff").Value = (DateTimePicker1.Value)

End Sub

You really just need that one line.....data will be in the grid, just a lot less code.....

Lianeliang answered 29/11, 2016 at 18:26 Comment(1)
This works great, except how do you line up the picker with the underlying cell if the cell is in a datagridview?Lammergeier
F
2

Ok... Using some of @rajat and @Aaron examples, i made one that pops up on the DateTimePicker cell. Thanks everyone.

Private Sub DataGridView1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick

    If e.ColumnIndex = 8 Then 'CHECK IF IT IS THE RIGHT COLUMN

        'SET SIZE AND LOCATION
        Dim rect = DataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True)
        DateTimePicker1.Size = New Size(rect.Width, rect.Height)
        DateTimePicker1.Location = New Point(rect.X + 10, rect.Y + 76) 'USE YOU OFFSET HERE

        DateTimePicker1.Visible = True
        ActiveControl = DateTimePicker1

    End If

End Sub


Private Sub DateTimePicker1_ValueChanged(sender As Object, e As EventArgs) Handles DateTimePicker1.ValueChanged

    If DataGridView1.RowCount > 0 Then 'JUST TO AVOID FORM LOAD CRASH

        DataGridView1.CurrentCell.Value = DateTimePicker1.Value.ToShortDateString
        DateTimePicker1.Visible = False

    End If
Fried answered 11/3, 2020 at 19:23 Comment(0)
X
1

To solve some entry issues when using the DateTimePicker in a DataGridView you will want to add the following to the Microsoft Sample referenced above. It took quite a while to search out the problems with the valuechanged event not firing as expected. The fix came from here (stackoverflow) and translated to C# below. It seemed appropriate to add this information here as I keep finding this forum post when searching on DataGridView and DateTimePicker.

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {

        switch (keyData & Keys.KeyCode)
        {
            case Keys.Enter:
            case Keys.Tab:
                this.dataGridView.Focus();
                break; 
        }

        return base.ProcessCmdKey(ref msg, keyData);

    }
Xenophon answered 29/12, 2015 at 18:41 Comment(0)
C
1

Use RowsAdded Event shown as below-

 private void dgvEducationalData_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
    {
        DataGridViewRow row = dgvEducationalData.Rows[e.RowIndex];
        Console.WriteLine("Rows added");
        if (e.RowIndex != -1)
        {
            foreach (DataGridViewCell cell in row.Cells)
                if (cell.ColumnIndex == 2 || cell.ColumnIndex == 1)
                {

                    dateTimePicker = new DateTimePicker();
                    dateTimePicker.Font = new Font("Segoe UI", 10);
                    dgvEducationalData.Controls.Add(dateTimePicker);
                    dateTimePicker.Format = DateTimePickerFormat.Short;
                    Rectangle oRectangle = dgvEducationalData.GetCellDisplayRectangle(cell.ColumnIndex, e.RowIndex, true);
                    dateTimePicker.Size = new Size(oRectangle.Width - 2, oRectangle.Height - 10);
                    dateTimePicker.Location = new Point(oRectangle.X, oRectangle.Y);

                }
        }
    }

enter image description here

Confidence answered 17/11, 2022 at 8:27 Comment(0)
P
0

I think the CloseUp event on DateTimePicker is more appropriate because the changed value is triggering on any change while CloseUp only triggers when the entire date is selected

Palomino answered 1/12, 2016 at 8:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.