Change Date in DataGridViewCell using Arrow Keys

john noble 221 Reputation points
2022-12-22T13:43:12.873+00:00

Hi Folks,

On my winForm, I have a DatagridView that has a date column. Dates are presented as UK style 25/12/2022 (for Christmas Day)

When the user enters the cell, I would like my program to be able to change the date by the use of the arrow keys. So if the user presses the Up Arrow the date would change to 24/12/2022. If the user presses the down arrow it would change to 26/12/2022.

I have done something similar with a masked Textbox where I override the ProcessCmdKey event like so...

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)  
{  
     // User uses arrow keys to select date  
        string dateString = this.Text;  
        string format = "dd/MM/yyyy";  
        DateTime tempDate;  
        if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out tempDate))  
           {  
      
               // Add / Subtract a day  
               if (keyData == Keys.Up)  
               {  
                   tempDate = tempDate.AddDays(1);  
                   this.Text = tempDate.ToShortDateString();  
                   return true;  
               }  
      
               if (keyData == Keys.Down)  
               {  
                   tempDate = tempDate.AddDays(-1);  
                   this.Text = tempDate.ToShortDateString();  
                   return true;  
               }  
      }  
}  

Except I'm not sure how to apply this to a DataGridViewCell.

Any ideas ?

Thanks,

John

Developer technologies | Windows Forms
{count} votes

2 answers

Sort by: Most helpful
  1. Reza Aghaei 4,996 Reputation points Volunteer Moderator
    2022-12-27T03:57:46.837+00:00

    Note: In this post, I assume you have seen How to: Host Controls in Windows Forms DataGridView Cells which shows how you can create a datetime picker for your DataGridView. So this post is trying to show how to handle Up and Down arrow key while editing the cell.

    --------------

    Handle arrow keys while editing the cell - Add or Subtract day by UP and Down key

    In the default implementation of DataGridViewTextBoxEditingControl, when it receives arrow keys, using the EditingControlWantsInputKey method, it decide whether it should let the key be handled by the editing control, or should it pass the arrow key to DataGridView; for example when the user press down arrow, if there's no new line in the edit control, then it pass the down arrow key to the DataGridView, otherwise, let the control handle it which goes to the next line of text. The default handling of Up and Down arrow keys in TextBox is moving the caret to next or previous line if available, or if there's no line available, move to left or right.

    To change the behavior and run a custom logic when the use press Up or Down arrow keys, you need to do the following:

    1. You need to change the logic of editing control to not pass the Up and Down arrow keys keys to DataGridView
    2. You need to override the default handling of Up and Do

    The first thing, creating a custom editing control, to disable passing Up and Down to DataGridView:

    using System;  
    using System.Windows.Forms;  
    public class MyDataGridViewTextBoxColumn : DataGridViewTextBoxColumn  
    {  
        public MyDataGridViewTextBoxColumn()  
        {  
            this.CellTemplate = new MyDataGridViewTextBoxCell();  
        }  
    }  
    public class MyDataGridViewTextBoxCell : DataGridViewTextBoxCell  
    {  
        public override Type EditType => typeof(MyDataGridViewTextBoxEditingControl);  
    }  
    public class MyDataGridViewTextBoxEditingControl : DataGridViewTextBoxEditingControl  
    {  
        public override bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey)  
        {  
            if ((keyData == Keys.Up) || (keyData == Keys.Down))  
                return true;  
            return base.EditingControlWantsInputKey(keyData, dataGridViewWantsInputKey);  
        }  
    }  
    

    Then in the next step, make sure you add this column to your DataGridView in designer or in code:

    dataGridView1.Columns.Add(new MyDataGridViewTextBoxColumn() { DataPropertyName = "ColumnName", HeaderText = "Header Text" });  
    

    Then what you need is handling the KeyDown event of the editing control, and run your custom logic. To to do, make sure you handle the EditingControlShowing event of the DataGridView in designer or in the code:

    dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;  
    

    And there, Handle KeyDown event of the EditingControl:

    private void DataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)  
    {  
        var cell = dataGridView1.CurrentCell;  
        var edit = e.Control as TextBox;  
        if (cell != null && cell.ColumnIndex == 0 && edit != null)  
        {  
            edit.KeyDown -= edit_KeyDown; //Make sure it handles the event once  
            edit.KeyDown += edit_KeyDown;  
        }  
    }  
    private void edit_KeyDown(object sender, KeyEventArgs e)  
    {  
        if (e.KeyData == Keys.Up || e.KeyData == Keys.Down)  
        {  
            e.Handled = true;  
            e.SuppressKeyPress = true;  
            MessageBox.Show("You custom logic goes here!");  
        }  
    }  
    

    Now the control shows the expected behavior:

    • In edit mode, for your specific column, Up and Down doesn't move to the top or bottom cell
    • In normal mode, arrow keys work as expected and move between cells
    • Up and Down arrow and have been handled and a custom logic runs.

    Now your custom logic. First make sure you handle the CellFormatting and CellParsing, which are responsible to show the data in the desired format, and later after editing, convert it back to the desired value of the data source:

    dataGridView1.CellFormatting += DataGridView1_CellFormatting;  
    dataGridView1.CellParsing += DataGridView1_CellParsing;  
    

    Then I use this logic:

    private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)  
    {  
        if (e.ColumnIndex == 0 && e.RowIndex >= 0)  
        {  
            e.CellStyle.Format = "dd/MM/yyyy";  
        }  
    }  
    private void DataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)  
    {  
        if (e.ColumnIndex == 0 && e.RowIndex >= 0)  
        {  
            if(DateTime.TryParseExact((string)e.Value,  
                "dd/MM/yyyy",  
                Thread.CurrentThread.CurrentUICulture,  
                System.Globalization.DateTimeStyles.None,  
                out DateTime d))  
            {  
                e.Value = d;  
                e.ParsingApplied = true;  
            }  
        }  
    }  
    

    Now it's time for modifying the Up and Down arrow logic in the edit_KeyDown event handler:

    private void edit_KeyDown(object sender, KeyEventArgs e)  
    {  
        if (e.KeyData == Keys.Up || e.KeyData == Keys.Down)  
        {  
            e.Handled = true;  
            var txt = (TextBox)sender;  
            if (DateTime.TryParseExact(txt.Text,  
                "dd/MM/yyyy",  
                Thread.CurrentThread.CurrentUICulture,  
                System.Globalization.DateTimeStyles.None,  
                out DateTime d))  
            {  
                var dx = e.KeyData == Keys.Up ? +1 : -1;  
                txt.Text = d.AddDays(dx).ToString("dd/MM/yyyy");  
            }  
        }  
    }  
    

    There you go!


  2. Karen Payne MVP 35,596 Reputation points Volunteer Moderator
    2022-12-27T12:29:58.133+00:00

    See my code sample which uses customer columns.

    274326-screen1.png

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.