none
DATAGRIDVIEW CELL EDIT RRS feed

  • Question

  • When you are editing a cell, any action that makes the cell lose focus (e.g. Enter) generates the following sequence of events:

    CellLeave
    CellValidating
    CellParsing (if the contents has changed)
    CellEndEdit

    As a result the cell contents is validated and accepted.

    If the Form hosting DataGridView is closed while editing a cell, this implies that the cell loses focus and the sequence above takes place. Then a partially edited cell will be accepted as valid. On my opinion this is not what we want: the cell editing should be canceled instead. To this purpose I tried the following:

            private void ListRFP_FormClosing(object sender, FormClosingEventArgs e)
            {
                dataGridView1.CancelEdit();  //** USELESS
            }

    But I do not get the expected result, because the program enters this handler only after the sequence above; then:

    1. The call CancelEdit is useless because editing is already terminated at this point;
    2. Closing of the Form accepts a partially edited cell, which probably does not contain the desired information.

    In the CellValidating you can insert the instruction e.Cancel = true; that forces return to the editing, then the Form will not close and await for user input. Granted that the user may simply press Esc to cancel editing, I definitely would prefer a 'more professional' approach.

    Any clue?




    • Edited by GiorgioITA Monday, April 1, 2019 9:07 AM
    Monday, April 1, 2019 9:07 AM

Answers

  • The solution is very simple; in the Form that contains the DataGridView component, add:

            protected override void WndProc(ref Message msg)
            {
                if (msg.Msg == 0x0010 /*WM_CLOSE*/)
                {
                    dataGridView1.CancelEdit();
                }
                base.WndProc(ref msg);
            }

    Pressing the button 'X" or Alt-F4 issues the message WM_CLOSE that will CancelEdit; AFTER THAT base.WndProc will leave focus etc.




    • Edited by GiorgioITA Saturday, October 26, 2019 7:50 AM
    • Marked as answer by GiorgioITA Saturday, October 26, 2019 7:50 AM
    Saturday, October 26, 2019 7:50 AM

All replies

  • Hi GiorgioITA,

    Thank you for posting here.

    >>1. The call CancelEdit is useless because editing is already terminated at this point;

    DataGridView.CancelEdit Method cancels edit mode for the currently selected cell and discards any changes.

    >>2. Closing of the Form accepts a partially edited cell, which probably does not contain the desired information.

    I suggest you to use get the original value and the new value, you could check the code sample in the link below.

    https://stackoverflow.com/questions/24702413/how-can-i-retrieve-the-previous-value-of-a-datagridview-cell-using-the-cellvalue

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, April 2, 2019 8:03 AM
    Moderator
  • Here is a simple example that I used for test. The DataGridView contains only one column and validation consists in verifying that the cell is not blank. I omit the Designer code which is straightforward: if you want to run this test, you must simply create a form with a DataGridView and a Button.

    using System;
    using System.Windows.Forms;
    using System.Diagnostics;
    /*
     * Simplified example of DataGridView, with only one column.
     * This form is supposed to be called from within some other form.
     * Parsing should commit the input (if changed) to an underlying database.
     */
    namespace TestDataGridViewEdit
    {
        public partial class TestDGV : Form
        {
            private string old_value;
            public TestDGV()
            {
                InitializeComponent();
            }
            private void TestDGV_Load(object sender, EventArgs e)
            {
                // setup
                dataGridView1.ColumnCount = 1;
                dataGridView1.Columns[0].Name = "ITEMS";
                dataGridView1.RowHeadersVisible = false;
                // populate DataGridView
                for (int i = 1; i <= 5; i++)
                {
                    dataGridView1.Rows.Add("Item " + i.ToString());
                }
            }
            private void TestDGV_FormClosing(object sender, FormClosingEventArgs e)
            {
                Debug.WriteLine("FORM CLOSING");
                dataGridView1.CancelEdit();  //** USELESS
                Debug.WriteLine(old_value);  //** Restore value in database
            }
            private void button1_Click(object sender, EventArgs e)
            {
                dataGridView1.CancelEdit();  //** USELESS
                Debug.WriteLine("BUTTON CLICK");
            }
            private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
            {
                Debug.WriteLine("BEGIN EDIT");
                old_value = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
            }
            private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
            {
                Debug.WriteLine("END EDIT");
            }
            private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
            {
                Debug.WriteLine("CELL LEAVE");
            }
            private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
            {
                Debug.WriteLine("VALIDATING");
                if (String.IsNullOrWhiteSpace(e.FormattedValue as string))
                {
                    Debug.WriteLine("NULL STRING");
                    e.Cancel = true;
                }
            }
            private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
            {
                Debug.WriteLine("PARSING");
                //** Commit input to database
            }
        }
    }

    This form is supposed to be launched from within another form, that's why I am so concerned with the form closing issue.

    If you close the program  that runs this test, it kills every ongoing editing and open form without passing through the sequence LEAVE - VALIDATING, hence the ongoing editing is cancelled.
    On the contrary, it appears from my tests that when you close the form TestDGV, it launches the event FormClosing after other actions - to include changing the focus, hence the validation and accept sequence.

    1 >> "DataGridView.CancelEdit Method cancels edit mode for the currently selected cell and discards any changes." you should add "if the cell currently is in edit mode." - otherwise CancelEdit has no effect, as you can verify by commenting out the two lines marked USELESS.

    2. I like the idea of saving the old_value in the cell, however it does not completely fix the issue, for if the validation fails. as e.Cancel is used in CellValidating, then return to editing is forced and the Form will not close; if the user presses Esc, the changes to the cell are discarded, but the Form remains open.

    If I were able to capture an indication that the form is about to close at an earlier stage, I could easily solve this problem.




    • Edited by GiorgioITA Wednesday, April 3, 2019 8:20 AM
    Wednesday, April 3, 2019 8:20 AM
  • Hi GiorgioITA,

    >>If I were able to capture an indication that the form is about to close at an earlier stage, I could easily solve this problem.

    If you save the all then data when you do the change, maybe it would be helpful. Saving the original data to a table instead of using CellValidating.

    What does the "capture an indication that the form is about to close at an earlier stage" mean?

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, April 8, 2019 7:45 AM
    Moderator
  • "If I were able to capture an indication that the form is about to close at an earlier stage, I could easily solve this problem."

    Explanation:

    Form fires the event Form_Closing after having completed other tasks - to include terminating edit mode. I wish an event such as "Form_about_to_close" existed, that fires before any other task - then I could use it to invoke CancelEdit.

    I understand that I have to live with the features available in the library. The user shall be made aware that closing the form while in edit mode is equivalent to accept its content - albeit possibly incomplete. Besides, this behavior is consistent e.g. to clicking another cell.




    • Edited by GiorgioITA Tuesday, April 9, 2019 2:35 PM
    Tuesday, April 9, 2019 2:34 PM
  • Hi GiorgioITA,

    You could invoke a method with include the CancelEdit before you trigger the closing event.

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, April 22, 2019 7:27 AM
    Moderator
  • The solution is very simple; in the Form that contains the DataGridView component, add:

            protected override void WndProc(ref Message msg)
            {
                if (msg.Msg == 0x0010 /*WM_CLOSE*/)
                {
                    dataGridView1.CancelEdit();
                }
                base.WndProc(ref msg);
            }

    Pressing the button 'X" or Alt-F4 issues the message WM_CLOSE that will CancelEdit; AFTER THAT base.WndProc will leave focus etc.




    • Edited by GiorgioITA Saturday, October 26, 2019 7:50 AM
    • Marked as answer by GiorgioITA Saturday, October 26, 2019 7:50 AM
    Saturday, October 26, 2019 7:50 AM