Home > Articles > Programming > Windows Programming

  • Print
  • + Share This
This chapter is from the book

Utilizing Cell-Oriented Grid Features

You have probably noticed that the DataGridView is much more focused at the cell level that its DataGrid predecessor was. Part of the reason for this is that a frequent use of grids is where columns don’t necessarily dictate the structure of the grid’s content. Specifically, users want spreadsheet-like functionality that mimics the interaction model millions of people have become accustomed to with programs like Microsoft Excel and other spreadsheet applications.

Once again, the DataGridView comes to the rescue and makes supporting that model fairly easy. You have already seen some of the cell-level events that let you control what is displayed at the cell level (CellFormatting event) and that tell you when users interact with a cell by editing the contents (EditControlShowing event) or simply click on it (CellClick event). You can set different context menus and tooltips down to the cell level, so that every cell can become a distinct entity in the grid from the users’ perspective. There are actually over 30 events raised by the DataGridView that expose interactions and modifications at the cell level that you can subscribe to for providing cell-oriented features.

Additionally, there are different selection modes that you can use to change the way the grid highlights cells, columns, or rows when the user clicks in different places in the grid. The SelectionMode property on the grid determines the selection behavior and is of type DataGridViewSelectionMode. The DataGridView control supports the selection modes (described in Table 6.6). While you can’t combine these modes (the enumeration isn’t a Flags enumerated type), you can achieve a combination of modes by using the SelectionMode property on the grid plus some additional event handling. Regardless of which of these modes you select, clicking on the upper left header cell (the one that is above the row header cells and to the left of the column header cells) selects all the cells in the grid.

DataGridViewSelectionMode Enumeration Values

Value

Description

CellSelect

This mode lets you select one or many cells in the grid using the mouse or keyboard. If you click in any cell, just that cell will be selected. You can click and drag, and contiguous cells that you drag over will also be selected. If you click in one cell, then Shift-click in another, you will select the entire contiguous set of cells from the first click to the second. You can even select noncontiguous cells by holding down the Ctrl key while you click cells. This is the default selection mode.

FullRowSelect

Clicking in any cell in the grid will select all of the cells in the entire row that contains the cell and will deselect any cells outside the row.

FullColumnSelect

Clicking in any cell in the grid will select all of the cells in the entire column that contains the cell and will deselect any cells outside the column.

RowHeaderSelect

Clicking on the row header cell will select the entire row, but otherwise this selection mode behaves like CellSelect. This is the mode set by the designer for a grid when you add it to a form.

ColumnHeaderSelect

Clicking on the column header cell will select the entire column, but otherwise this selection mode behaves like CellSelect.

As an example of a more cell-oriented application, the download code includes an application called SimpleSpread. This application mimics a simple spreadsheet and lets you do summations of the numeric values in a cell. It uses a combination of selection mode and some event handling to give you a similar selection experience to most spreadsheets—specifically, it acts like a combination of RowHeaderSelect and ColumnHeaderSelect, even though you can’t achieve that through the SelectionMode property alone. The SimpleSpread sample application is shown in Figure 6.10.

06fig10.jpg

Figure 6.10 SimpleSpread Sample Application

As you can see, the application lets you enter numbers into the cells; then you can select a sequence of cells and press the Sum button in the tool strip control at the top to get it to calculate the sum and place that in the next cell to the right or below the sequence of selections. As Figure 6.10 shows, this application even supports selecting rectangular groups of cells, and it will compute the summation in both the row and column directions. The logic is nowhere near complete to handle all combinations of selections and cell contents, but it gives you a good idea of how to set something like this up.

To code this up (as shown in Listing 6.6), I had to do a few things that are different from your average DataGridView application. As I mentioned, I wanted to support a spreadsheet-like selection model, where you can select individual cells, but that selecting a column or row header would select the entire column or row, respectively. To do this, I set the SelectionMode for the grid to RowHeaderSelect, turned off sorting for all the columns as I created them and added them to the grid, and then handled the ColumnHeaderMouseClick event to manually select all the cells in a column when the user clicks on a column header.

Example 6.6. Spreadsheet-Oriented Grid Column Selection Support

public partial class SimpleSpreadForm : Form
{
   public SimpleSpreadForm()
   {
      InitializeComponent();
      m_Grid.SelectionMode =
         DataGridViewSelectionMode.RowHeaderSelect;
   }

   private void OnFormLoad(object sender, EventArgs e)
   {
      int start = (int)'A';
      for (int i = 0; i < 26; i++)
      {
         string colName = ((char)(i + start)).ToString();
         int index = m_Grid.Columns.Add(colName, colName);
         m_Grid.Columns[i].SortMode =
            DataGridViewColumnSortMode.NotSortable;
         m_Grid.Columns[i].Width = 75;
      }
      for (int i = 0; i < 50; i++)
      {
        m_Grid.Rows.Add();
      }
   }

   private void OnColumnHeaderMouseClick(object sender,
      DataGridViewCellMouseEventArgs e)
   {
      m_Grid.ClearSelection();
      foreach (DataGridViewRow row in m_Grid.Rows)
      {
         row.Cells[e.ColumnIndex].Selected = true;
      }
   }
   ...
}

In this case, I just programmatically added some rows and columns to the grid, set the column headers to be the letters of the alphabet, and turned off sorting on the column by setting the SortMode property to NotSortable. If you were going to support very large spreadsheets, you might need to maintain an in-memory sparse array, and only render the cells as you need them (which you could do with virtual mode) to avoid the overhead of maintaining a large number of cells, their contents, and their selections if the grid will be sparsely populated.

To get the row numbers to display in the row headers, I handled the RowAdded event and set the header cell value in that handler:

private void OnRowAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
   m_Grid.Rows[e.RowIndex].HeaderCell.Value = e.RowIndex.ToString();
}

Another selection mode you might want to support is to have hot cells, meaning that the selection of cells changes as you move the mouse around the grid without having to click. To do this, you could just handle the CellMouseEnter and CellMouseLeave events, selecting and deselecting the cell under the mouse in those handlers, respectively.

  • + Share This
  • 🔖 Save To Your Account