Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Event to prevent C# DataGridView from changing the current row

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?

like image 785
Peter Avatar asked Jul 24 '13 09:07

Peter


People also ask

What does event stopPropagation () do?

The event. stopPropagation() method stops the bubbling of an event to parent elements, preventing any parent event handlers from being executed. Tip: Use the event. isPropagationStopped() method to check whether this method was called for the event.

Why we use event preventDefault () in react?

The preventDefault() method cancels the event if it is cancelable, meaning that the default action that belongs to the event will not occur. For example, this can be useful when: Clicking on a "Submit" button, prevent it from submitting a form.

What is event preventDefault () and event stopPropagation ()?

preventDefault() prevents the browsers default behaviour, but does not stop the event from bubbling up the DOM. The event. stopPropagation() prevents the event from bubbling up the DOM, but does not stop the browsers default behaviour.

What is the opposite of event preventDefault ()?

As you probably might have already worked out based on the simple explanation above: the opposite of event. preventDefault() is nothing. You just don't prevent the event, by default the browser will allow the event if you are not preventing it.


3 Answers

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;
    }
like image 79
Mike Avatar answered Oct 12 '22 23:10

Mike


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.

like image 33
CristisS Avatar answered Oct 12 '22 22:10

CristisS


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.

like image 29
Peter Avatar answered Oct 12 '22 22:10

Peter