Event to prevent C# DataGridView from changing the current row

13,489

Solution 1

After trying lots of different things I came to the solution that the easiest and (for me) best working solution would be to check which control is focused in the RowValidating event of the DataGridView. This solution addresses exactly the problem I had: the RowValidating event was thrown by clicking other buttons for example. There are still some special cases which cause the RowValidating event to arise even if the current row isn't changing (sorting the DataGridView by clicking a column header, for example) but I think I can live with this minor issues. Maybe a future version of .NET will implement a DataGridView with a RowLeaving event which can be cancelled.

Solution 2

Just Ran into a similar issue and after many attempts my only work around was to use "Enter and Leave" to know when the form was NotActive to avoid Validating - Luckily the firing order was before the row\col level events

HTH - Mike

    private bool IsActive = false;

    private void dgbList_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
    {
        if (IsActive)
        {
            if (Do_I_NeedTo_Cancel)
              e.Cancel = true;
        }
    }

    private void dgList_Leave(object sender, EventArgs e)
    {
        IsActive = false;
    }

    private void dgList_Enter(object sender, EventArgs e)
    {
        IsActive = true;
    }

Solution 3

I think your best option is to use RowValidating with a bool condition to check if you call .Validate().

EDIT

Per your last comment, why not add a check for dataGridView.IsCurrentRowDirty? For example:

private void dataGridView1_RowValidating(object sender, DataGridViewCellCancelEventArgs e) {
    if (dataGridView1.IsCurrentRowDirty) {
        if (dataCheck())
            if (MessageBox.Show("Ok?", "Save?", MessageBoxButtons.YesNoCancel) == DialogResult.Cancel) {
                e.Cancel = true;
            }
    }
}

If there is no dirty data, no matter who calls the validation the dataCheck won't be made and the messageBox will not appear.

EDIT

You can replace the 'if' clauses with any check you want, including one for dataGridView2.

You can also extend the dataGridView control if you have very complicated requirements.

EDIT

I now understand your requirement. I don't think there is a quick and clean solution. I would use the SelectionChanged event and there set the logic to prevent the change. Something like:

//rember the selection of the index
private int _currentIndex;
private bool _rollingBackSelection;

private void SelectionChanged(...){
     //when changing back to the selection in dgv1 prevent dgv2 check
     if (_rollingBackSelection) {
         _rollingBackSelection = false;
         return;
     }
     if (dgv2IsDirty()) {
          var result = MessageBox.Show("Ok?", "Save?", MessageBoxButtons.YesNoCancel);
          if (result == DialogResult.Cancel) {
             _rollingBackSelection = true;
             //rollback to the previous index
             dgv1.Rows[_currentIndex].Selected = true;
             return;
          }
          if (result == DialogResult.Yes)
             dgv2Save();
         dgv2Load();
         _currentIndex = dgv1.SelectedRows[0].Index;
     }
}

I think something like above is your best shot.

Share:
13,489
Peter
Author by

Peter

Updated on July 08, 2022

Comments

  • Peter
    Peter almost 2 years

    I would need an event that fires when the current row of a System.Windows.Forms.DataGridView is going to be changed and which allows me to cancel this change, e.g. by setting the Cancel-property of the EventArgs to true.

    I know about the CurrentCellChanged (the row has already changed when the event is called) and the RowLeave (no possibility to cancel the leave-operation) events, but neither provide what I would need. I also tried to use the RowValidating event, but this event is also called when the row is just going to be validated (without the intention to leave it), for example when I call <ParentForm>.Validate(), which leads to many confusions.

    Is there any other possibility or a clean(er) solution to get the desired behaviour?