1.1 Border styles
With the DataGridView control, you can customize the appearance of the control's border and gridlines to improve the user experience. You can modify the gridline color and the control border style in addition to the border styles for the cells within the control. The gridline color is controlled via the GridColor property. You can also apply different cell border styles for ordinary cells, row header cells, and column header cells. For advanced border styles the DataGridView provides the advanced border style properties as well.
Note: The gridline color is used only with the Single, SingleHorizontal, and SingleVertical values of the DataGridViewCellBorderStyle enumeration and the Single value of the DataGridViewHeaderBorderStyle enumeration. The other values of these enumerations use colors specified by the operating system. Additionally, when visual styles are enabled on Windows XP and above, the GridColor property value is not used.
1.1.1 Standard Border Styles
Standard border styles are controlled via the CellBorderStyle, RowHeadersBorderStyle, and ColumnHeadersBorderStyle properties.
The following table identifies the standard border styles available via the :
BorderStyle value |
Description |
Fixed3D |
A three-dimensional border. |
FixedSingle |
A single-line border. |
None |
No border. |
1.1.2 Advanced Border Styles
The DataGridView control allows you to fully customize its appearance, including the borders of the cells and headers. The DataGridView has CellBorderStyle, ColumnHeadersBorderStyle, and RowHeadersBorderStyle properties that allow you to set the appearance of the cell border. However, if you need to further customize the borders, the DataGridViewAdvancedBorderStyle class allows you to set the style of the border on the individual sides of the cells. The Left, Right, Top, and Bottom properties of DataGridViewAdvancedBorderStyle represent the left, right, top, and bottom border of a cell, respectively. You can set these properties on the AdvancedCellBorderStyle, AdvancedColumnHeadersBorderStyle, AdvancedRowHeadersBorderStyle properties of the DataGridView to produce various appearances for the borders between the cells.
The following table identifies the advanced border styles available that can be set for the left, right, top and bottom parts. Note that some combinations are not valid.
BorderStyle value |
Description |
Inset |
A three-dimensional border. |
InsetDouble |
A single-line border. |
None |
No border. |
NotSet |
The border is not set |
Outset |
A single-line raised border |
OutsetDouble |
A double-line raised border |
OutsetPartial |
A single-line border containing a raised portion |
Single |
A single-line border |
1.2 Enter-Edit modes
By default, users can edit the contents of the current DataGridView text box cell by typing in it or pressing F2. This puts the cell in edit mode if all of the following conditions are met:
- The underlying data source supports editing.
- The DataGridView control is enabled.
- The EditMode property value is not EditProgrammatically.
- The ReadOnly properties of the cell, row, column, and control are all set to false.
In edit mode, the user can change the cell value and press ENTER to commit the change or ESC to revert the cell to its original value.
You can configure a DataGridView control so that a cell enters edit mode as soon as it becomes the current cell. The behavior of the ENTER and ESC keys is unchanged in this case, but the cell remains in edit mode after the value is committed or reverted. You can also configure the control so that cells enter edit mode only when users type in the cell or only when users press F2. Finally, you can prevent cells from entering edit mode except when you call the BeginEdit method.
The following table describes the different edit modes available:
EditMode value |
Description |
EditOnEnter |
Editing begins when the cell receives focus. This mode is useful when pressing the TAB key to enter values across a row, or when pressing the ENTER key to enter values down a column. |
EditOnF2 |
Editing begins when F2 is pressed while the cell has focus. This mode places the selection point at the end of the cell contents. |
EditOnKeystroke |
Editing begins when any alphanumeric key is pressed while the cell has focus. |
EditOnKeystrokeOrF2 |
Editing begins when any alphanumeric key or F2 is pressed while the cell has focus. |
EditProgrammatically |
Editing begins only when the BeginEdit method is called. |
1.3 Clipboard copy modes
When you enable cell copying, you make the data in your DataGridView control easily accessible to other applications through the Clipboard. The DataGridView control copies the text representation of each selected cell to the Clipboard. This value is the cell value converted to a string or, for image cells, the value of the Description property. The content is then added to the Clipboard as tab-delimited text values for pasting into applications like Notepad and Excel, and as an HTML-formatted table for pasting into applications like Word.
You can configure cell copying to copy cell values only, to include row and column header text in the Clipboard data, or to include header text only when users select entire rows or columns.
The following table identifies the different clipboard copy modes:
Clipboard Copy modes |
Description |
Disable |
Copying to the Clipboard is disabled. |
EnableAlwaysIncludeHeaderText |
The text values of selected cells can be copied to the Clipboard. Header text is included for rows and columns that contain selected cells. |
EnableWithAutoHeaderText |
The text values of selected cells can be copied to the Clipboard. Row or column header text is included for rows or columns that contain selected cells only when the SelectionMode property is set to RowHeaderSelect or ColumnHeaderSelect and at least one header is selected. |
EnableWithoutHeaderText |
The text values of selected cells can be copied to the Clipboard. Header text is not included. |
Depending on the selection mode, users can select multiple disconnected groups of cells. When a user copies cells to the Clipboard, rows and columns with no selected cells are not copied. All other rows or columns become rows and columns in the table of data copied to the Clipboard. Unselected cells in these rows or columns are copied as blank placeholders to the Clipboard.
When users copy content, the DataGridView control adds a DataObject to the Clipboard. This data object is retrieved from the GetClipboardContent() method. You can call this method when you want to programmatically add the data object to the Clipboard. The GetClipboardContent() method retrieves values for individual cells by calling the DataGridViewCell.GetClipboardContent() method. You can override either or both of these methods in derived classes to customize the layout of copied cells or to support additional data formats.
1.4 Frozen columns/rows
When users view data sometimes they need to refer to a single column or set of columns frequently. For example, when displaying a table of customer information that contains many columns, it is useful to display the customer name at all times while enabling other columns to scroll outside the visible region.
To achieve this behavior, you can freeze columns in the control. This is done via setting the Frozen property on the column or row. When you freeze a column, all the columns to its left (or to its right in right-to-left language scripts) are frozen as well. Frozen columns remain in place while all other columns can scroll. Rows act in similar fashion: all rows before the frozen row are frozen as well and remain in place while the non frozen rows can scroll.
1.5 Implementing Custom cells and editing controls/cells
You can implement the IDataGridViewEditingCell interface in your derived cell class to create a cell type that has editing functionality but does not host a control in editing mode. To create a control that you can host in a cell in editing mode, you can implement the IDataGridViewEditingControl interface in a class derived from Control.
1.5.1 IDataGridViewEditingControl
Cells that support advanced editing functionality typically use a hosted control that is derived from a Windows Forms control. This interface is implemented by editing controls, such as DataGridViewComboBoxEditingControl and DataGridViewTextBoxEditingControl, that are hosted by the corresponding DataGridView cells, such as DataGridViewComboBoxCell and DataGridViewTextBoxCell, when they are in edit mode.
Cell types that can that host editing controls set their EditType property to a Type representing the editing control type.
1.5.2 IDataGridViewEditingCell
This interface is implemented by classes to provide a user interface (UI) for specifying values without hosting an editing control. The UI in this case is displayed regardless of whether the cell is in edit mode. The DataGridViewCheckBoxCell is an example of a cell that implements the IDataGridViewEditingCell interface.
Other cell types, such as DataGridViewButtonCell, provide a UI but do not store user-specified values. In this case, the cell type does not implement IDataGridViewEditingCell or host an editing control.
1.6 Virtual mode
With virtual mode, you can manage the interaction between the DataGridView control and a custom data cache. To implement virtual mode, set the VirtualMode property to true and handle one or more of the events described in this topic. You will typically handle at least the CellValueNeeded event, which enables the control look up values in the data cache.
1.6.1 Bound Mode and Virtual Mode
Virtual mode is necessary only when you need to supplement or replace bound mode. In bound mode, you set the DataSource property and the control automatically loads the data from the specified source and submits user changes back to it. You can control which of the bound columns are displayed, and the data source itself typically handles operations such as sorting.
1.6.2 Supplementing Bound Mode
You can supplement bound mode by displaying unbound columns along with the bound columns. This is sometimes called "mixed mode" and is useful for displaying things like calculated values or user-interface (UI) controls.
Because unbound columns are outside the data source, they are ignored by the data source's sorting operations. Therefore, when you enable sorting in mixed mode, you must manage the unbound data in a local cache and implement virtual mode to let the DataGridView control interact with it.
1.6.3 Common questions and scenarios
1) How do I show unbound data along with bound data?
2) How do I show data that comes from two tables?
1.6.4 Replacing Bound Mode
If bound mode does not meet your performance needs, you can manage all your data in a custom cache through virtual-mode event handlers. For example, you can use virtual mode to implement a just-in-time data loading mechanism that retrieves only as much data from a networked database as is necessary for optimal performance. This scenario is particularly useful when working with large amounts of data over a slow network connection or with client machines that have a limited amount of RAM or storage space.
1.6.5 Virtual-Mode Events
If your data is read-only, the CellValueNeeded event may be the only event you will need to handle. Additional virtual-mode events let you enable specific functionality like user edits, row addition and deletion, and row-level transactions.
Some standard DataGridView events (such as events that occur when users add or delete rows, or when cell values are edited, parsed, validated, or formatted) are useful in virtual mode, as well. You can also handle events that let you maintain values not typically stored in a bound data source, such as cell ToolTip text, cell and row error text, cell and row shortcut menu data, and row height data.
The following events occur only when the VirtualMode property is set to true.
Event |
Description |
CellValueNeeded |
Used by the control to retrieve a cell value from the data cache for display. This event occurs only for cells in unbound columns. |
CellValuePushed |
Used by the control to commit user input for a cell to the data cache. This event occurs only for cells in unbound columns. Call the UpdateCellValue method when changing a cached value outside of a CellValuePushed event handler to ensure that the current value is displayed in the control and to apply any automatic sizing modes currently in effect. |
NewRowNeeded |
Used by the control to indicate the need for a new row in the data cache. |
RowDirtyStateNeeded |
Used by the control to determine whether a row has any uncommitted changes. |
CancelRowEdit |
Used by the control to indicate that a row should revert to its cached values. |
The following events are useful in virtual mode, but can be used regardless of the VirtualMode property setting.
Events |
Description |
UserDeletingRow UserDeletedRow RowsRemoved RowsAdded |
Used by the control to indicate when rows are deleted or added, letting you update the data cache accordingly. |
CellFormatting CellParsing CellValidating CellValidated RowValidating RowValidated |
Used by the control to format cell values for display and to parse and validate user input. |
CellToolTipTextNeeded |
Used by the control to retrieve cell ToolTip text when the DataSource property is set or the VirtualMode property is true. Cell ToolTips are displayed only when the ShowCellToolTips property value is true. |
CellErrorTextNeeded RowErrorTextNeeded |
Used by the control to retrieve cell or row error text when the DataSource property is set or the VirtualMode property is true. Call the UpdateCellErrorText method or the UpdateRowErrorText method when you change the cell or row error text to ensure that the current value is displayed in the control. Cell and row error glyphs are displayed when the ShowCellErrors and ShowRowErrors property values are true. |
CellContextMenuStripNeeded RowContextMenuStripNeeded |
Used by the control to retrieve a cell or row ContextMenuStrip when the control DataSource property is set or the VirtualMode property is true. |
RowHeightInfoNeeded RowHeightInfoPushed |
Used by the control to retrieve or store row height information in the data cache. Call the UpdateRowHeightInfo method when changing the cached row height information outside of a RowHeightInfoPushed event handler to ensure that the current value is used in the display of the control. |
1.6.6 Best Practices in Virtual Mode
If you are implementing virtual mode in order to work efficiently with large amounts of data, you will also want to ensure that you are working efficiently with the DataGridView control itself. See below for more information on best practices
1.7 容量(Capacity)
In general, the DataGridView does not have any hard-coded capacity limits. The grid was designed so that more and more content can be added as machines become faster and have more memory. That said, the grid was not designed to deal with large number of columns. If you add more than 300 columns you will start to notice a degradation in performance as our performance tuning of the grid was not designed for this. If you need a grid with large amounts of columns then the DataGridView might not meet your needs. Regarding the number of rows supported, the DataGridView is bound by memory constraints. When using Virtual mode you can easily support over 2 million rows. Check out the best practices section below for information on things you can do (and not do) to improve memory usage and performance.
2 最佳实践(Best Practices)
The DataGridView control is designed to provide maximum scalability. If you need to display large amounts of data, you should follow the guidelines described in this topic to avoid consuming large amounts of memory or degrading the responsiveness of the user interface (UI).
2.1 Using Cell Styles Efficiently
Each cell, row, and column can have its own style information. Style information is stored in DataGridViewCellStyle objects. Creating cell style objects for many individual DataGridView elements can be inefficient, especially when working with large amounts of data. To avoid a performance impact, use the following guidelines:
· Avoid setting cell style properties for individual DataGridViewCell or DataGridViewRow objects. This includes the row object specified by the RowTemplate property. Each new row that is cloned from the row template will receive its own copy of the template's cell style object. For maximum scalability, set cell style properties at the DataGridView level. For example, set the DefaultCellStyle property rather than the DataGridViewCell.Style property.
· If some cells require formatting other than default formatting, use the same DataGridViewCellStyle instance across groups of cells, rows, or columns. Avoid directly setting properties of type DataGridViewCellStyle on individual cells, rows, and columns. For an example of cell style sharing, see How to: Set Default Cell Styles for the Windows Forms DataGridView Control. You can also avoid a performance penalty when setting cell styles individually by handling the CellFormatting event handler. For an example, see How to: Customize Data Formatting in the Windows Forms DataGridView Control.
· When determining a cell's style, use the DataGridViewCell.InheritedStyle property rather than the DataGridViewCell.Style property. Accessing the Style property creates a new instance of the DataGridViewCellStyle class if the property has not already been used. Additionally, this object might not contain the complete style information for the cell if some styles are inherited from the row, column, or control. For more information about cell style inheritance, see Cell Styles in the Windows Forms DataGridView Control.
2.2 Using Shortcut Menus Efficiently
Each cell, row, and column can have its own shortcut menu. Shortcut menus in the DataGridView control are represented by ContextMenuStrip controls. Just as with cell style objects, creating shortcut menus for many individual DataGridView elements will negatively impact performance. To avoid this penalty, use the following guidelines:
· Avoid creating shortcut menus for individual cells and rows. This includes the row template, which is cloned along with its shortcut menu when new rows are added to the control. For maximum scalability, use only the control's ContextMenuStrip property to specify a single shortcut menu for the entire control.
· If you require multiple shortcut menus for multiple rows or cells, handle the CellContextMenuStripNeeded or RowContextMenuStripNeeded events. These events let you manage the shortcut menu objects yourself, allowing you to tune performance.
2.3 Using Automatic Resizing Efficiently
Rows, columns, and headers can be automatically resized as cell content changes so that the entire contents of cells are displayed without clipping. Changing sizing modes can also resize rows, columns, and headers. To determine the correct size, the DataGridView control must examine the value of each cell that it must accommodate. When working with large data sets, this analysis can negatively impact the performance of the control when automatic resizing occurs. To avoid performance penalties, use the following guidelines:
· Avoid using automatic sizing on a DataGridView control with a large set of rows. If you do use automatic sizing, only resize based on the displayed rows. Use only the displayed rows in virtual mode as well.
· For rows and columns, use the DisplayedCells or DisplayedCellsExceptHeaders field of the DataGridViewAutoSizeRowsMode, DataGridViewAutoSizeColumnsMode, and DataGridViewAutoSizeColumnMode enumerations.
· For row headers, use the AutoSizeToDisplayedHeaders or AutoSizeToFirstHeader field of the DataGridViewRowHeadersWidthSizeMode enumeration.
· For maximum scalability, turn off automatic sizing and use programmatic resizing.
2.4 Using the Selected Cells, Rows, and Columns Collections Efficiently
The SelectedCells collection does not perform efficiently with large selections. The SelectedRows and SelectedColumns collections can also be inefficient, although to a lesser degree because there are many fewer rows than cells in a typical DataGridView control, and many fewer columns than rows. To avoid performance penalties when working with these collections, use the following guidelines:
· To determine whether all the cells in the DataGridView have been selected before you access the contents of the SelectedCells collection, check the return value of the AreAllCellsSelected method. Note, however, that this method can cause rows to become unshared. For more information, see the next section.
· Avoid using the Count property of the DataGridViewSelectedCellCollection to determine the number of selected cells. Instead, use the GetCellCount() method and pass in the DataGridViewElementStates.Selected value. Similarly, use the DataGridViewRowCollection.GetRowCount() and DataGridViewColumnCollection.GetColumnCount() methods to determine the number of selected elements, rather than accessing the selected row and column collections.
· Avoid cell-based selection modes. Instead, set the SelectionMode property to FullRowSelect or FullColumnSelect.
2.5 Using Shared Rows
Efficient memory use is achieved in the DataGridView control through shared rows. Rows will share as much information about their appearance and behavior as possible by sharing instances of the DataGridViewRow class.
While sharing row instances saves memory, rows can easily become unshared. For example, whenever a user interacts directly with a cell, its row becomes unshared. Because this cannot be avoided, the guidelines in this topic are useful only when working with very large amounts of data and only when users will interact with a relatively small part of the data each time your program is run.
A row cannot be shared in an unbound DataGridView control if any of its cells contain values. When the DataGridView control is bound to an external data source or when you implement virtual mode and provide your own data source, the cell values are stored outside the control rather than in cell objects, allowing the rows to be shared.
A row object can only be shared if the state of all its cells can be determined from the state of the row and the states of the columns containing the cells. If you change the state of a cell so that it can no longer be deduced from the state of its row and column, the row cannot be shared.
For example, a row cannot be shared in any of the following situations:
· The row contains a single selected cell that is not in a selected column.
· The row contains a cell with its ToolTipText or ContextMenuStrip properties set.
· The row contains a DataGridViewComboBoxCell with its Items property set.
In bound mode or virtual mode, you can provide ToolTips and shortcut menus for individual cells by handling the CellToolTipTextNeeded and CellContextMenuStripNeeded events.
The DataGridView control will automatically attempt to use shared rows whenever rows are added to the DataGridViewRowCollection. Use the following guidelines to ensure that rows are shared:
· Avoid calling the Add(Object[]) overload of the Add method and the Insert(Object[]) overload of the Insert method of the Rows collection. These overloads automatically create unshared rows.
· Be sure that the row specified in the RowTemplate property can be shared in the following cases:
§ When calling the Add() or Add(Int) overloads of the Add method or the Insert(Int, Int) overload of the Insert method of the Rows collection.
§ When increasing the value of the RowCount property.
§ When setting the DataSource property.
· Be sure that the row indicated by the indexSource parameter can be shared when calling the AddCopy, AddCopies, InsertCopy, and InsertCopies methods of the Rows collection.
· Be sure that the specified row or rows can be shared when calling the Add(DataGridViewRow) overload of the Add method, the AddRange method, the Insert(Int32,DataGridViewRow) overload of the Insert method, and the InsertRange method of the Rows collection.
To determine whether a row is shared, use the DataGridViewRowCollection.SharedRow(Int) method to retrieve the row object, and then check the object's Index property. Shared rows always have an Index property value of –1.
2.6 Preventing Rows from Becoming Unshared
Shared rows can become unshared as a result of code or user action. To avoid a performance impact, you should avoid causing rows to become unshared. During application development, you can handle the RowUnshared event to determine when rows become unshared. This is useful when debugging row-sharing problems.
To prevent rows from becoming unshared, use the following guidelines:
· Avoid indexing the Rows collection or iterating through it with a foreach loop. You will not typically need to access rows directly. DataGridView methods that operate on rows take row index arguments rather than row instances. Additionally, handlers for row-related events receive event argument objects with row properties that you can use to manipulate rows without causing them to become unshared.
· If you need to access a row object, use the DataGridViewRowCollection.SharedRow(Int) method and pass in the row's actual index. Note, however, that modifying a shared row object retrieved through this method will modify all the rows that share this object. The row for new records is not shared with other rows, however, so it will not be affected when you modify any other row. Note also that different rows represented by a shared row may have different shortcut menus. To retrieve the correct shortcut menu from a shared row instance, use the GetContextMenuStrip method and pass in the row's actual index. If you access the shared row's ContextMenuStrip property instead, it will use the shared row index of -1 and will not retrieve the correct shortcut menu.
· Avoid indexing the DataGridViewRow.Cells collection. Accessing a cell directly will cause its parent row to become unshared, instantiating a new DataGridViewRow. Handlers for cell-related events receive event argument objects with cell properties that you can use to manipulate cells without causing rows to become unshared. You can also use the CurrentCellAddress property to retrieve the row and column indexes of the current cell without accessing the cell directly.
· Avoid cell-based selection modes. These modes cause rows to become unshared. Instead, set the SelectionMode property to DataGridViewSelectionMode.FullRowSelect or DataGridViewSelectionMode.FullColumnSelect.
· Do not handle the DataGridViewRowCollection.CollectionChanged or RowStateChanged events. These events cause rows to become unshared. Also, do not call the DataGridViewRowCollection.OnCollectionChanged(CollectionChangeEventArgs) or OnRowStateChanged(Int,DataGridViewRowStateChangedEventArgs) methods, which raise these events.
· Do not access the SelectedCells collection when the SelectionMode property value is FullColumnSelect, ColumnHeaderSelect, FullRowSelect, or RowHeaderSelect. This causes all selected rows to become unshared.
· Do not call the AreAllCellsSelected(boolean) method. This method can cause rows to become unshared.
· Do not call the SelectAll method when the SelectionMode property value is CellSelect. This causes all rows to become unshared.
· Do not set the ReadOnly or Selected property of a cell to false when the corresponding property in its column is set to true. This causes all rows to become unshared.
· Do not access the DataGridViewRowCollection.List property. This causes all rows to become unshared.
- Do not call the Sort(IComparer) overload of the Sort method. Sorting with a custom comparer causes all rows to become unshared.