Working with the DataGridView


Working with the DataGridView

The DataGridView is much like its predecessor in that it provides for a grid-like display of rows and columns of data from an underlying data source. That's where the similarity ends. If you have worked very much with .NET 1.0 and 1.1 DataGrids, you know that despite their power, you almost always ended up having to create cumbersome controls and templates and classes just to get the grid to do what you needed. The frustration of trying to shoehorn the DataGrid to fit into the design of your application is over. This section shows you how to create not only powerful and fast grids of data, but visually compelling ones as well.

DataGridView Basics

You've seen the most basic example of how to get a DataGridView up and running: drag a table from your Data Sources window onto a form and a BindingNavigator, BindingSource, and DataGridView will appear on the form. The DataGridView will automatically display all of the columns in the table, which is typically not the behavior you want.

Before getting into a basic example of binding with the DataGridView, you should have a quick look at some of the events, methods, and properties of this control. Table 37.5 lists the events, Table 37.6 lists the methods, and Table 37.7 lists the properties. By looking at this information, you may begin to see how to do some of the more complex things with the DataGridView. For a complete list of all events, and methods, and properties, see the MSDN documentation that came with your copy of Visual Studio 2005 or the online MSDN documentation at http://msdn.microsoft.com.

Table 37.5. Some of the Events Published by the DataGridView

Event

Description

CancelRowEdit

Event is fired when a row edit is cancelled.

CellBeginEdit

Occurs when the selected cell goes into edit mode.

CellClick

Occurs when a cell is clicked; includes any part of the cell such as the border.

CellContentClick

Occurs only when the cell's inner content is clicked.

CellContentDoubleClick

Occurs when the cell's inner content is double-clicked.

CellDoubleClick

Event is fired when a cell is double-clicked.

CellEndEdit

Occurs when the selected cell leaves edit mode.

CellFormatting

Event is fired when a cell needs to be formatted for rendering. Use this for custom cell formatting that is far easier than the old DataGrid.

CellPainting

Occurs when a cell needs to be painted.

CellValueChanged

Occurs when the value of a cell changes.

DataBindingComplete

Occurs when the data-binding operation for the control is complete.

DefaultValuesNeeded

This event is fired when the user enters the row for new records, requiring default values to appear.

Scroll

This event is fired when the user scrolls the control's view.

SelectionChanged

Occurs when the user's current selection changes.

UserAddedRow

This event is fired when the user has finished adding a row to the DataGridView.

UserDeletedRow

This event is fired when the user has finished removing a row from the DataGridView.

UserDeletingRow

This event is fired when the user starts to delete a row from the DataGridView.


Table 37.6. Some of the Methods of DataGridView

Method

Description

BeginEdit

Places the currently selected cell into edit mode

CancelEdit

Cancels the editing of the currently selected cell

ClearSelection

Clears the current selection

CommitEdit

Commits changes pending in the current cell edit without stopping edit mode

EndEdit

Commits changes pending in the current cell and stops edit mode

HitTest

Returns hit test information based on X and Y coordinates including the Row and Column at the given coordinates

SelectAll

Selects all cells in the DataGridView

Sort

Sorts the DataGridView


Table 37.7. Some of the Properties of DataGridView

Property

Description

AllowUserToAddRows

A Boolean indicating whether the user can create new rows in the DataGridView

AllowUserToDeleteRows

Indicates whether the user can remove rows

AllowUserToOrderColumns

Indicates whether the user can change the order of columns

AllowUserToResizeColumns

Indicates whether the user can change the size of columns

AllowUserToResizeRows

Indicates whether the user can change the height of the rows

AlternatingRowsDefaultCellStyle

Gets or sets the default style of odd-numbered rows

AutoGenerateColumns

Indicates whether the DataGridView will automatically generate display columns for each data column

ColumnCount

Gets or sets the number of displayed columns

Columns

Gets the collection that contains all columns in the control

CurrentCell

Gets or sets the currently selected cell

CurrentRow

Gets the row in which the currently selected cell resides

DataMember

The name of the table or list within the data source to which the grid is bound

DataSource

The data source to which the grid is bound

DefaultCellStyle

Defines the default style (such as foreground, background, font, and so on) for cells

EditMode

Indicates what user action should trigger edit mode

MultiSelect

Indicates whether the user can select more than one cell at a time

NewRowIndex

Gets the index that will be used for the next new row

ReadOnly

Indicates whether the grid is read-only

Rows

Accesses the collection of rows associated with the grid

VirtualMode

Indicates whether the developer has provided their own custom data management routines


As mentioned earlier, there are many more properties, methods, and events that provide the DataGridView with its power. In the rest of this section you will see a few of these properties in the context of some practical and common samples.

Using a ComboBox Column in a DataGridView

Those of you who have worked with the 1.1 version of the DataGrid know that there were quite a few limitations on its usefulness. For example, in a room full of developers, only the bravest (or most foolish, depending on who you ask) would volunteer to write the code to allow their DataGrid to support combo boxes, drop-down image lists, check boxes, and more. In fact, most people simply resorted to buying more powerful grids from component vendors.

That kind of custom grid programming is no longer a problem with the DataGridView. As you'll see in this and subsequent sections, the DataGridView was designed from the ground up to allow programmers to customize, tweak, and extend it.

The sample in this section involves creating a column in the DataGridView that uses a ComboBox. This model is used when the column in the underlying data source is a number or some other key into a lookup table (such as a state code, an order number, a color code, and so on). This sample literally took me five minutes to create.

To start off, create a new Windows Application (C# of course). For that new application create a new DataSet that looks like the DataSet shown in Figure 37.3.

Figure 37.3. A contacts DataSet to illustrate a lookup column in a DataGridView.


After you have the ContactsDS dataset created, drag it onto the surface of the main form and then delete the BindingNavigator tool strip. Modify the columns list and edit the ContactTypeID column. Change the header text to "Contact Type." Then change the ColumnType property to DataGridViewComboBoxColumn. You should notice that a few new properties have appeared for this column under the Data category:

  • DataSource The data source that supplies the items for the ComboBox.

  • DisplayMember The name of the member on the list item that will be displayed in the ComboBox.

  • Items A collection that allows you to manually configure the list of items in the ComboBox.

  • ValueMember The name of the member on the list item that will be used as the current value of the selected item in the ComboBox.

For this sample, set DataSource to the ContactTypes table. You can browse to this table and it will create a component called ContactTypesBindingSource and bind to that. Set the DisplayMember to Description and ValueMember to ContactTypeID. You can even set DisplayStyle to Nothing, which will actually hide the drop-down button until the cell goes into edit mode (this makes the column appear as a regular text column until the user clicks into it).

That's ityou just created a column in a DataGridView that is an integer field that gets the list of available options from another table and displays that list in a ComboBoxand you didn't have to write a single line of code. This kind of task is brutal and painful in .NET 1.1 but really couldn't be simpler using the new DataGridView control.

To make the sample do something interesting, add the following lines of code to the Form_Load event to add a few contact types:

contactsDS.ContactTypes.AddContactTypesRow("Personal Contact"); contactsDS.ContactTypes.AddContactTypesRow("Business Contact"); 


Take a look at this application in action as shown in Figure 37.4. The Save Data button shown in Figure 37.4 is just a simple button that takes the data being managed by the application and stores it in an XML file that can then be read later.

Figure 37.4. The ComboBox column in action.


Advanced Cell Customization

Another grid feature that often makes developers cringe is the notion of customizing the appearance of a cell such as its background color, font, and more. In this next example, which builds on the previous ComboBox example, you will see just how much you can do with the new DataGridView with very little effort on your part.

If you ever tried to implement ledger-style coloring in a Windows Forms DataGrid, you know that it's not as easy as you like, especially if you know how easy it is to accomplish with the v1.1 ASP.NET DataGrid. You can now accomplish a ledger-style coloring in just a few seconds. In the DataGridView properties, edit the AlternatingRowsDefaultCellStyle property by clicking the ellipsis ("...") button. Set the background color to yellow and run the application. You should now have a ledger-style grid without writing any extra code.

Another task that normally frustrates programmers working with the old DataGrid is conditionally formatting a single cell. For this example, assume that you are required to change the background color of the "Age" cell to Aquamarine if the person in that row is 35 or older. For this, all you have to do is handle the CellFormatting event, as shown in the following code snippet:

private void contactsDataGridView_CellFormatting(     object sender,     DataGridViewCellFormattingEventArgs e) {     // return if the column being formatted isn't one we're interested in         if (e.RowIndex < 0) return;         if (e.ColumnIndex != contactsDataGridView.Columns["Age"].Index) return;         if ((e.Value == null) ||             (e.Value == DBNull.Value)) return;         if (e.RowIndex == contactsDataGridView.NewRowIndex) return;         int age = (int)e.Value;           // we know this is the "Age" column, so this is a safe typecast to assume         if (age >= 35)           e.CellStyle.BackColor = Color.Aquamarine; } 


The CellFormatting event is called every time the cell needs to be formatted for output. This gives you the chance to change any of the properties of the cell to which you have access.

However, if you need to do something slightly more complicated, such as formatting that requires a Graphics object, you need to use the CellPainting event. Don't worry; using the CellPainting event is nowhere near as painful as modifying the Paint event of the old DataGrid.

In the code snippet that follows, you see an example of a CellPainting event handler that creates a gradient background for the LastName column:

private void contactsDataGridView_CellPainting( object sender, DataGridViewCellPaintingEventArgs e) {     if (e.RowIndex < 0) return;     if (e.ColumnIndex != contactsDataGridView.Columns["LastName"].Index) return;     // if item is selected, use default painting     if ((e.State & DataGridViewElementStates.Selected) ==        DataGridViewElementStates.Selected)        return;     Rectangle rect = new Rectangle(e.CellBounds.X, e.CellBounds.Y,                                    e.CellBounds.Width - 1, e.CellBounds.Height - 1);     using (LinearGradientBrush lgb =       new LinearGradientBrush(rect, Color.White, Color.LightCoral, 0f))     {       e.Graphics.FillRectangle(lgb, rect);     }     // if there's no value to draw, return     if ((e.Value == null) || (e.Value == DBNull.Value)) return;     using (Pen pen = new Pen(contactsDataGridView.GridColor))     {       e.Graphics.DrawRectangle(pen, e.CellBounds.X - 1, e.CellBounds.Y - 1,         e.CellBounds.Width, e.CellBounds.Height);     }     // now draw the value     StringFormat sf = new StringFormat();     sf.LineAlignment = StringAlignment.Center;     sf.Alignment = StringAlignment.Near;     using (Brush valueBrush = new SolidBrush(e.CellStyle.ForeColor))     {     e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font, valueBrush, rect, sf);   }   e.Handled = true; } 


A little bit of GDI+ code was used in the preceding example to create the gradient and use a few brushes, but it's all pretty basic stuff. Using GDI+ in this manner requires that your application have a reference to System.Drawing.Drawing2D. The really important line of code is

e.Handled = true; 


This tells the DataGridView that you have handled the painting for the cell in question. When Handled is true, the DataGridView will not render the default cell style painting. If you left Handled to false, all of the painting you did in this event handler would be overwritten by the default cell style for that cell.

Figure 37.5 shows the new DataGridView, complete with the ComboBox column, the ledger style, and the gradient-background cell.

Figure 37.5. The DataGridView with advanced cell customization.


The DataGridView "Unbound"

Perhaps one of the most interesting features of the DataGridView is that you can actually use this control without binding it to any data. When you drag a DataGridView onto a form without specifying a data source, you can then use the Smart Tag or the Columns property to start adding unbound columns. To add an unbound column, all you have to do is specify the name of the column, the header text, and the cell's template (TextBox, ComboBox, CheckBox, Image, and so on). After you've done that, you're ready to programmatically add rows to the grid. You can do this in a couple of ways. The following few lines of code show a few of the different ways to get rows into the grid:

dataGridView1.Rows.Add(new object[] { "Kevin", "Hoffman" }); dataGridView1.Rows.Add(); dataGridView1.Rows.Add(9); 


The first line of code adds a row and prepopulates the columns with values. The object array's indices must correspond to the column indices or the data might not show up properly. The second line simply adds a new, empty row. The third line adds nine empty rows to the end of the data in the grid.

After you have programmatically placed your own rows into the grid (or the user does it for you), all of the code you've seen in this chapter dealing with the DataGridView will also work on an unbound grid. This means that you can change the formatting and painting behavior of an unbound cell as well as create a look-up ComboBox column just as easily as if it was a bound control.



Microsoft Visual C# 2005 Unleashed
Microsoft Visual C# 2005 Unleashed
ISBN: 0672327767
EAN: 2147483647
Year: 2004
Pages: 298

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net