Printer Friendly Version      Send     
Click to Rate and Give Feedback
Related Articles
Here we explain how the new hierarchyID data type in SQL Server 2008 helps solve some of the problems in modeling and querying hierarchical information.

By Kent Tegels (September 2008)
We introduce you to the benefits of building composite applications with the Composite Application Guidance for WPF from Microsoft patterns & practices.

By Glenn Block (September 2008)
ADO.NET Data Services provide Web-accessible endpoints that allow you to filter, sort, shape, and page data without having to build that functionality yourself.

By Shawn Wildermuth (September 2008)
See how routed events and routed commands in Windows Presentation Foundation form the basis for communication between the parts of your UI.

By Brian Noyes (September 2008)
More ...
Articles by this Author
This month Dino builds a service layer that authenticates users of Silverlight 2 and ASP.NET AJAX services to prevent illegal access to sensitive back-end services.

By Dino Esposito (September 2008)
Dino Esposito compares the use of AJAX patterns and DOM manipulations to the use of the ASP.NET partial rendering engine.

By Dino Esposito (August 2008)
In this installment, the author provides an enhanced implementation of the BST pattern and compares it to HTM solutions.

By Dino Esposito (July 2008)
AJAX is meant to go beyond mere partial page rendering. Find out where Dino Esposito thinks dynamic pages are headed in the future with ASP.NET AJAX.

By Dino Esposito (June 2008)
This month we begin a look at the Single Page Interface (SPI) model and some design patterns for designing AJAX applications.

By Dino Esposito (May 2008)
This month, use nested ListView controls to create hierarchical views of data and extend the eventing model of the ListView by deriving a custom ListView class.

By Dino Esposito (April 2008)
This month Dino Esposito shows you how to get Windows-style modal dialog boxes for your Web applications thanks to the Ajax Control Toolkit and some clever coding.

By Dino Esposito (Launch 2008)
This month Dino looks at AJAX control extenders again, adding more advanced features including masked editing and autocompletion.

By Dino Esposito (February 2008)
More ...
Popular Articles
Here we explain how the new hierarchyID data type in SQL Server 2008 helps solve some of the problems in modeling and querying hierarchical information.

By Kent Tegels (September 2008)
The goal of the ADO.NET Data Services Framework is to create a simple REST-based framework for exposing and consuming data-centric services easily.

By Elisa Flasko and Mike Flasko (August 2008)
Efficient parallel applications aren’t born by merely running an old app on a parallel processor machine. Tuning needs to be done if you’re to gain maximum benefit.

By Rahul V. Patil and Boby George (June 2008)
Learn how to automate custom SharePoint application deployments, use the SharePoint API, and avoid the hassle of custom site definitions.

By E. Wilansky, P. Olszewski, and R. Sneddon (May 2008)
More ...
Read the Blog
SQL Server 2008 supports a new data type, HierarchyID, that helps solve some of the problems in modeling and querying hier­archical information. In the September 2008 issue of MSDN Magazine, Kent Tegels introduces you to the ...
Read more!
Many people using SharePoint technologies don't realize that there is auditing support built directly into the Windows SharePoint Services (WSS) 3.0 platform. In the September 2008 issue of MSDN Magazine, Ted Pattison walks you through a ...
Read more!
The September 2008 issue of MSDN Magazine is now available online. Here's what's in the issue: Hierarchy ID: Model ...
Read more!
Silverlight 2 features a rich and robust control model that is the basis for the controls included in the platform and for third-party control packages. You can also use this control model to build controls of your own. In the August 2008 issue of MSDN Magazine, Jeff Prosise describes how to ...
Read more!
In the August 2008 issue of MSDN Magazine, Matt Milner covers several topics regarding development with Windows Workflow Foundation, some that are intended to address specific reader questions, such as how to safely share a persistence database ...
Read more!
LINQ is a powerful tool enabling quick filtering data based on a standard query language. It can tear through a structured set of data using a simple and straightforward syntax. In the August 2008 issue of MSDN Magazine, Jared Parsons demonstrates a ...
Read more!
More ...
Cutting Edge
A New Grid Control in Windows Forms
Dino Esposito

Code download available at: CuttingEdge0504.exe (191 KB)
Browse the Code Online
Grid controls are essential in many of today's apps. Until now, though, most developers using Visual Basic® have had to buy third-party components to get an effective, easy to use grid component. The Windows® Forms DataGrid turned out to lack too many features for the average developer. Third-party grid controls are often more feature-rich than anything found in a system framework like the Microsoft® .NET Framework. But for in-house and personal applications that don't need a professional quality control, the new DataGridView in the forthcoming .NET Framework 2.0 is a viable alternative.
The DataGridView control is the successor to the Windows Forms DataGrid version 1.x. Once you have dropped the control onto a Windows Form, you'll see the popup window shown in Figure 1. You can declaratively set a number of features—add new rows, edit and delete the current row, reorder columns, bind the control to its data, and style it as needed.
Figure 1 DataGridView Smart Tag 
The DataGridView class allows customization of cells, rows, columns, and borders through properties such as DefaultCellStyle, ColumnHeadersDefaultCellStyle, CellBorderStyle, and GridColor. This alone exceeds the capabilities of the Windows Forms DataGrid version 1.x.
You can use a DataGridView control to display data with or without an underlying data source. If you don't specify a data source, you can create columns and rows that contain data and add them directly to the DataGridView using the control's user interface. Alternatively, you can set the usual DataSource and DataMember properties, bind the control to a data source, and have it automatically populated with data.
The DataGridView eliminates the most commonly reported snags of the previous version, including data caching. In version 1.x, there are no special capabilities for working with a very large amount of data. You have to either bind the control to the whole DataSet or implement a hand-written caching system. In the .NET Framework 2.0, the DataGridView control can work in virtual mode. Setting the VirtualMode property to true enables the control to display a subset of the available data (you can also use VirtualMode to provide a mix of bound and unbound columns).
You create a DataGridView with a set number of rows and columns and then handle the CellValueNeeded event to populate the cells. Virtual mode requires the implementation of an underlying data cache to handle the population, editing, and deletion of DataGridView cells based on actions of the user. As you can see, the mechanism is not entirely automatic but is much simpler than in version 1.x.
Data binding takes advantage of some new IDE features available in Visual Studio® 2005. As you can see in Figure 2, any data-bound Windows control can be bound to a variety of data sources—server databases such as SQL Server, local databases like Microsoft Access or SQL Server 2005 files, Web service methods, or custom business objects. The object that gets bound to the control is always a collection; the preceding data sources are just the storage media. Visual Studio 2005 generates classes and code to contain bindable data. In doing so, it requires you to select the data entities to use from the selected source.
Figure 2 Data Source Config Wizard 
Figure 3 shows the dialog box for picking up a table from a Microsoft Access database. Around that table, Visual Studio 2005 would construct an XSD schema file to represent a typed DataSet. In addition, the typed DataSet would be empowered with additional methods to load data on demand, optionally in parameterized way.
Figure 3 Declaring the Data Source 
The wizard and the options shown in Figure 2 and Figure 3 might change before the .NET Framework 2.0 ships. That's why I'll just give you the big picture here. To show you the new DataGridView control in action, I'll examine a handwritten data layer in which ADO.NET classes retrieve any data and custom collection objects convey data to the grid control.

Building a Simple Data Layer
A key enhancement in the .NET Framework 2.0, generic types are especially useful for creating custom collections in a snap. In .NET, generics are programming elements that can work with a variety of data types. You specify the data type when you declare the element. Among other things, generics can be used to create strongly typed collections. Here's an example:
Public Class EmployeeCollection 
       Inherits Collection(Of Employee)
End Class
Suppose you want to create and bind an array of objects representing employee data. You load database records from an Employee table into an instance of the Employee class and group employees together within a custom collection (shown in Figure 4). To create a custom collection in .NET Framework 1.x, you derive a new class from CollectionBase and override a couple of members—at the very minimum, the indexer property Item and the method Add. This action requires you to write a great deal of code, and the actual collection is only apparently typed. In reality, the custom collection is an ArrayList object, and anything you add to it, or get from it, is cast to the proper type before use.
Generics provide a dual advantage when you're moving data across tiers. You write much less code, and the code you do write is easier to maintain. Performance is significantly improved because no boxing is required for value types and no cast is performed in order to access the object in a strongly typed fashion.
Figure 4 shows a simple data layer expressed as a custom collection and a load method. The data is captured using ADO.NET classes and then placed into individual Employee objects for binding to the grid. Should you go with the "manual" approach described here, or are you better off exploiting the design-time capabilities of Visual Studio 2005? Get the best of both worlds: compose all of your low-level ADO.NET code into a class with a few public methods to perform the usual database operations. Next, bind this intermediate class to the control using the Object option shown in Figure 2.
The following code snippet shows how to fill a EmployeeCollection object and bind it to an instance of the DataGridView control:
Dim loader As New DataHelper()
Dim data As EmployeeCollection = loader.Load()
DataGridView1.DataSource = data
Figure 5 shows the grid in action. It doesn't look much different from an old-style DataGrid control.
Figure 5 The DataGridView Control in Action 

Customizing the DataGridView Control
Can you spot a drawback in the grid shown in Figure 5? The titles and countries are listed through numbers instead of more intelligible names. On the other hand, those numbers are the visible sign of a sensible data schema. Those numbers, in fact, represent foreign keys from cross-referenced tables. From the database design point of view, so far so good, but what about grid rendering? You need to transform those numbers into names—the country, the title, or whatever else they might stand for. In the .NET Framework 1.x, you first create a custom column type through an ad hoc class and then you add it to the grid's column collection. The DataGridView control has both enhanced capabilities and a richer set of built-in column types.
Figure 6 Editing the Columns of the DataGridView Control 
Figure 6 shows how to change the column type and all the choices available. By default, a grid column is rendered using a textbox column just as in version 1.x. To effectively render foreign keys, you need a combobox column bound to a distinct data source and a different pair of display/value members. The dialog in Figure 6 lets you change the column type to DataGridViewComboBoxColumn. Once you've done so, you can add a few extra properties to the column class to fill the combobox with both bound and unbound values. For example, you can set the DataSource property of the DataGridViewComboBoxColumn to the object that contains the bound items—all the titles and the countries to choose from. The DisplayMember property indicates the field to display through the combobox; ValueMember indicates the field to get and set the real value on the master table. Figure 7 illustrates the result.
Figure 7 Managing Foreign Keys in a DataGridView Control 
In read-only mode, the combobox doesn't drop down and is limited to showing the bound value. (You can also make use of the combobox column's DisplayStyle property here to hide the drop-down arrow. This makes the UI look even better.) In edit mode, use the combobox to select the new value for the cell. If you have to change the country cell, you can pick up the new value from a list of country names rather than from a meaningless sequence of numbers.
In addition to combobox and classic textbox columns, you can also have image, link, and button columns. Link and button columns display their items as clickable elements. Each click on the contents of an item is bubbled up as a CellContentClick event.
Each column can have its own set of visual properties as shown in Figure 8. You can control padding, colors, fonts, and borders. Column settings can be set declaratively, programmatically on a per-column basis, or for all the columns at once through the DefaultCellStyle property.
Figure 8 Setting the Styles of a Column 
The following code snippet sets the background color for alternating rows to override the default background set for all cells. In addition, it sets the Format property on the HireDate column to cause the bound date object to be formatted as "Month, Year."
grid.DefaultCellStyle.BackColor = Color.LightGray;
grid.AlternatingRowsDefaultCellStyle.ForeColor = Color.White;
grid.AlternatingRowsDefaultCellStyle.BackColor = Color.Black;
grid.Columns["HireDate"].DefaultCellStyle.Format = "y";
The width of each column can be set in a relative manner, unlike in Windows Forms 1.x grids. Aside from assigning a column a given number of pixels, you can require that the column determine its width automatically and adjust it based on the displayed data. The property AutoSizeCriteria can be set to any of the following values: None, HeaderOnly, Rows, HeaderAndRows, and HeaderAndDisplayedRows. HeaderOnly and Rows indicate that the column should be wide enough to display the entire header or the largest row. HeaderAndRows takes into account the width of the header and that of the largest row. Finally, HeaderAndDisplayedRows considers only the displayed rows and the header.

Cell Templates
If the column types supported out-of-the-box by the new Windows Forms DataGridView control don't meet your needs, you can create your own column types with cells that host controls of your choice. Creating custom column types is possible in version 1.x; it's as easy as deriving a class from a known base class. In the .NET Framework 2.0, things are even easier because of a new infrastructure for templating.
One thing you won't find in the Beta 1 list of column types—the set is subject to change by the time the platform ships—is a calendar column to display and edit dates in an easy fashion. To create a calendar column, you must define a class that derives from DataGridViewColumn and extend it with a custom cell template. The cell template is the area that is occupied by individual grid cells. The content of the cell template depends on the user interface of the column. Link columns contain a hyperlink, standard columns include a textbox, combo columns make up their user interface with a combobox. A custom column populates the cell template with any combination of Windows controls. The cells of this column display dates in ordinary text cells, but when the user edits a cell, a DateTimePicker control appears, as in Figure 9. Let's see how to create a calendar column.
Figure 9 The Custom Calendar Column in Action 
In Figure 10, the CalendarColumn class inherits from DataGridViewColumn and overrides the CellTemplate property. The CellTemplate property returns a DataGridViewCell object that represents the content of the cell. As Figure 10 demonstrates, the CalendarColumn constructor uses a made-to-measure cell object—the CalendarCell class.
CalendarCell derives from the DataGridViewTextBoxCell class to avoid having to reimplement textbox display functionality. Alternatively, you can make it inherit from DataGridViewCell. The code for the CalendarCell class is split in two parts. One includes public properties such as the format of the date. The other portion of the code is the view editing control; that is, a class that derives from Control and implements the IDataGridViewEditingControl interface. This control provides the user interface when a particular cell enters into edit mode. For the CalendarCell, this user interface consists of a DateTimePicker control. For more details, take a look at the source code available for download from the link at the top of this article.
How can you use this new column with a DataGridView control? Once you bring the new column class into the project, it automatically becomes visible in the dropdown list of available column types. You can assign the calendar type to a column declaratively in the Visual Studio 2005 designer or proceed programmatically, as shown here:
Dim col As New CalendarColumn()
col.HeaderText = "Hire Date"
col.DataPropertyName = "HireDate"
Me.DataGridView1.Columns.Add(col)
The date picker control shows up only if the grid is working in edit mode. If the column is marked as read-only, the date picker remains hidden and the cell displays only static text.

The Data Connector
In the code download for this article, you'll see that the sample DataGridView is bound to a particular type of data source. A data source can be an enumerable data object or a data connector. The DataGridView accepts any of the following interfaces: IList, IListSource, IBindingList, IBindingListView.
IList and IListSource are old acquaintances to developers experienced in .NET. They are implemented by collections and special ADO.NET objects such as DataTable and DataSet. IBindingList has also been around since the .NET Framework 1.0 and derives from IList, adding support for change notification, AddNew semantics, and sorting (the new BindingList<T> generic class implements IBindingList). IBindingListView, new to the .NET Framework 2.0, further extends the IBindingList interface to add advanced sorting and filtering capabilities. The DataConnector class implements the IBindingListView interface.
In Windows Forms 2.0, the DataConnector component, renamed to BindingSource in Beta 2, is the data source object of choice; through it you can bind to a variety of data sources. You can bind the control to a data connector and have the connector component, in turn, bind to another data source or populate with data using a business object. The DataConnector binds to a physical data source through the DataSource and DataMember properties, as shown in the following code:
Me.EmployeesDataConnector.DataMember = "Employees"
Me.EmployeesDataConnector.DataSource = Me.MyEmployeesDataSet
When you connect a data source to a DataGridView control, Visual Studio 2005 creates three elements—the data connector, a data adapter, and a typed DataSet. The data adapter executes any query that fills the typed DataSet. The typed DataSet, in turn, is wrapped by the connector and populates the bound control.
The data connector provides a layer of abstraction between a Windows form and its data. All further interaction between form and data, including navigating, sorting, filtering, and updating, is performed through calls to the DataConnector.
As mentioned, a DataConnector encapsulates data and provides members for accessing that data. The Current property retrieves the current item; the property List retrieves the entire list. Currency management is handled automatically, but a number of related events are exposed anyway to allow for further customization. These events include CurrentItemChanged, CurrentChanged, DataSourceChanged, ListChanged, and BindingComplete.
It is worth noting that data sources bound to a DataConnector component can also be managed through the DataNavigator class. DataNavigator offers a VCR-like user interface for navigating the items of a list and performing a few common operations (Insert new, delete, update) on the currently selected record.

Sorting
The DataGridView class provides advanced sorting capabilities. Each column is given a SortMode property that determines whether the column is sortable or not. By default, all columns are sortable. To change this, set the SortMode property of a given column to NotSortable. You can do that both programmatically and declaratively at design time. The SortMode property also accepts two other values: Automatic (the default) and Programmatic. In both cases, sorting takes place in the default way, alphabetically. If automatic sorting is enabled, the sort direction glyph is displayed; otherwise, you have to show it yourself.
If the grid is configured for programmatic sorting, you have to rely on the sorting capabilities of the data source object in a data-bound scenario. If you're using a grid not bound to any data source, then you need to take care of the sorting yourself through the Sort method, shown here:
Dim titleComp As New TitleComparer
DataGridView1.Sort(titleComp)
The Sort method performs its magic by taking an instance of a class that implements the IComparer interface and determines the new order by comparing pairs of values.

Conclusion
All data-driven Windows and Web applications require a grid component. Grids need a good deal of extra functionality that the Windows Forms DataGrid control you get from the .NET Framework 1.x lacks. In the .NET Framework 2.0, the DataGridView control makes up for some of the limitations of the previous version. You'll find an improved user interface with more column types, more customization options, and even a virtual working mode that gets data only when required.
In this column I've only just scratched the surface of the DataGridView control with a sneak preview of the features that will be available with the next version of the .NET Framework. Note that the code and the discussion is based on the Beta 1 release and therefore all of the details are subject to change before the final release. In addition, you can almost certainly expect more features by the time the new version of the Windows Forms framework ships. Stay tuned.

Send your questions and comments for Dino to  cutting@microsoft.com.


Dino Esposito is a Wintellect instructor and consultant based in Italy. Author of Programming ASP.NET and the new book Introducing ASP.NET 2.0 (both from Microsoft Press), he spends most of his time teaching ASP.NET/ADO.NET classes and speaking at conferences. Get in touch with Dino at cutting@microsoft.com or join the blog at weblogs.asp.net/despos.

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker