Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

DataGridView Event Sequences

4.77/5 (35 votes)
3 Jan 2019CPOL7 min read 200.9K   11.6K  
A useful tool to help you understand DataGridView events as you navigate the DataGridView

Introduction

The DataGridView control generates many events as a user navigates the grid. There are cell entry/exit, row entry/exit, cell and row validation events, etc. To make best use of these events, you'll need to know when they occur, and what happens when you respond to these events in different ways. This article provides:

  • An application which contains a grid and an event log. By editing the grid, you will see the events generated in the log.
  • Finite state machine diagrams which describe the event sequence for the EditOnKeystroke edit mode.

Buttons are also provided which allow you to affect the behaviour of the event handlers. For example, a different sequence of events may be generated when a cell fails to validate. Changing those validation responses is just a click away.

The executable is provided in the download, so it's simple to try it out and see what events the DataGridView is firing at you.

I haven't supported every grid event, the log would be less useful if it were clogged up with all of them, but I've included the major navigation and validation events. Adding new handlers is trivial and explained below if you need to do it.

Let's take a look at the application first, then I'll describe the events in more detail and introduce the state machines.

Using the Application

DataGridView_Events/Dgv.jpg

The application contains an event log, a grid, and a tool bar. As soon as you run it up, grid events will fire and those events will be displayed in the log. Click on any cell in the grid and more events will be added to the log. The toolbar buttons can be used to simulate responses provided by the validation event handlers.

Toolbar Buttons

  • Cell Fail - When clicked, the Cell Fail state is enabled. Whenever an OnCellValidating event is handled, the handler will set the cancel flag to indicate validation failure. Click the button again to handle the event normally.
  • Row Fail - When clicked, the Row Fail state is enabled. Whenever an OnRowValidating event is handled, the handler will set the cancel flag to indicate validation failure. Click the button again to handle the event normally.
  • Grid Fail - When clicked, the Grid Fail state is enabled. Whenever an OnValidating event is handled, the handler will set the cancel flag to indicate validation failure. Click the button again to handle the event normally.
  • Reject Edit - When clicked, the Reject Edit state is enabled. Whenever an OnCellBeginEdit event is handled, the handler will set the cancel flag to indicate rejection of the edit. Click the button again to handle the event normally.
  • Log Clicks - When clicked, the Log Clicks state is enabled. This forces a blank line to be inserted in the log whenever the mouse is clicked. This often makes it easier to make sense of the logs because you can easily see which events were triggered since the last click.
  • Edit Mode - The grid supports a variety of edit modes. With each mode comes different event behaviour. Click on Auto Edit to cycle through the modes and the log will show you which mode is activated.
  • Clean Log - Just click this to empty the log. All logs will be lost. Copy (^C) works in the event log if you want to save the logs beforehand.

Using the Code

The code isn't complicated, and I'm not intending this article to be a grid programming tutorial so I won't go into it in detail. What you might want to do though is add/remove grid events.

In EventGrid.cs, you'll see the event handlers for the events I've supported, OnCellEnter(), OnCellBeginEdit(), etc. E.g.:

C#
protected override void  OnRowValidating(DataGridViewCellCancelEventArgs e)
{
    base.OnRowValidating(e);
    if (!ctrlInitialised)
    {
        return;
    }
    eventList.AddEvent("OnRowValidating (" + e.ColumnIndex + "," + e.RowIndex + 
                       ") - " + (form1.RowFail ? "FAIL" : "OK"));
    e.Cancel = form1.RowFail;
}

Each handler does the following:

  1. Calls the base event handler.
  2. Checks whether the grid is initialised.
  3. Calls eventList.AddEvent() with a string to be displayed in the log. My handlers put the cell index in the string where appropriate.
  4. Optionally modify a flag in the event arguments to indicate some behaviour specific to that event.

If you're not interested in the events I've supported, just delete the handler. If you want to support others, add a handler for the new event and follow the steps above.

Understanding DataGridView Events

Let's take a high level view of the event sequences and follow it up with a description of the state machine included in the downloads.

There are several variations to the general case, but let's start by assuming that the grid edit mode (DataGridView.EditMode) is EditOnKeystroke and that all cells, all rows, and the grid, are valid. That allows navigation of the grid without slipping into edit mode. As we move from one cell to another, we see (in this order):

1. Leave Events

The OnCellLeave() event will always occur when an attempt is made to navigate away from a cell. Additional Leave events may occur, depending on where we move to. For example:

  • Move to cell on same row - OnCellLeave()
  • Move to cell on different row - OnCellLeave(), OnRowLeave()
  • Set focus outside the grid - OnCellLeave(), OnRowLeave(), OnLeave() (this is the Grid leave event)

Leave events are straightforward, in the sense that future events are not affected by any change to arguments in the Leave event handler.

2. Validation Events

When the Leave events are complete, the Validation events will start to fire. Now, remember we're assuming successful validation here, so the Validating/Validated events occur in pairs, Validating followed by Validated. You'll recognise the order from above.

  • Move to cell on same row - OnCellValidating(), OnCellValidated()
  • Move to cell on different row - OnCellValidating(), OnCellValidated(), OnRowValidating(), OnRowValidated()
  • Set focus outside the grid - OnCellValidating(), OnCellValidated(), OnRowValidating(), OnRowValidated(), OnValidating(), OnValidated

3. Enter Events

Everything validated, so the cell focus can move as intended, and the event sequence completes by firing the Enter events for the new cell.

  • Move to cell on same row - OnCellEnter()
  • Move to cell on different row - OnRowEnter(), OnCellEnter()
  • Move to cell from outside the grid - OnRowEnter(), OnCellEnter(), OnEnter() (this is the Grid enter event)

Put all that together and when moving from a valid cell C1 in valid row R1 to cell C2 in row R2, the following sequence of events will fire:

  • OnCellLeave(C1)
  • OnRowLeave(R1)
  • OnCellValidating(C1)
  • OnCellValidated(C1)
  • OnRowValidating(R1)
  • OnRowValidated(R1)
  • OnRowEnter(R2)
  • OnCellEnter(C2)

Now as mentioned, that's just one case and there are many variations, so let's follow this case (i.e., moving to a cell in a different row) through the finite state machine (FSM). The FSM handles all variations for EditOnKeystroke, and when you're familiar with that, it isn't a great leap to EditOnEnter. More of that later, but now take a look at the master FSM in DgvFsmMasterEoK.pdf.

Begin at state 1 in the top left of the diagram. In this state, one of the cells is selected but not being edited. When a cell on another row is selected, the transition to state 5 occurs. This shows that the events OnCellLeave(), OnRowLeave(), and OnCellValidating() occur (in that order). State 5 is a sub-FSM you can find in DgvFsmA2.pdf. Now looking at FSM A2, from state 1 (assuming the OnCellValidating() handler indicates that the cell is valid), the transition to state 2 occurs. This transition shows that the events OnCellValidated() and OnRowValidating() occur. Next, assuming OnRowValidating() indicates that the row is valid, the events OnRowValidated(), OnRowEnter(), and OnCellEnter() occur, and the sub FSM exits back to master FSM state 1. The (old) and (new) arguments shown in the events on the diagram indicate whether the arguments provided in the event refer to the cell/row being exited (old) or entered (new).

Having worked through that example, you should now be able to experiment with variations (e.g., what happens when the OnRowValidating() event handler indicates that the row is invalid). Maybe try it with the app and follow it through on the FSM.

Edit on Enter

So what about changing the edit mode to EditOnEnter? Well, the main difference is at state 1 on the master FSM. State 1 is waiting for the user to select another cell or press a key to initiate edit mode for that cell. With EditOnEnter, this state becomes transient, i.e., there is no waiting because as soon as a cell is selected, it will enter edit mode automatically. There's no hanging around in state 1 anymore. The changes can be seen in DgvFsmMasterEoE.pdf. All inputs to state 1 now fire the event OnCellBeginEdit() as the last event before entering this state. Your OnCellBeginEdit() handler can reject the edit, leaving the cell selected in state 2, or accept it and enter edit mode in state 3 as previously. You may also notice that state 3 can no longer exit edit mode via the Escape key, which is ignored. There are no other differences, the sub-FSMs are not affected.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)