YOUR FEEDBACK
Werner Keil wrote: Java 6 update 10. If I'd be running Apple, I'd probably really drop dead...

SYS-CON.TV
TOP MICROSOFT .NET LINKS


Secrets of the .NET DataGrid
A look under the covers

If you're like many of us, the first time you played around with .NET's DataGrid component, you were wowed by its painless, yet powerful data-binding abilities and impressed with its overall simplicity and efficiency. But once you delved a little deeper into its functionality, you may have been surprised by the lack of features beyond dynamic data binding. Most applications require something more than a simple read-only static grid. Actually there are more complex, but less-documented features that the DataGrid provides that can be extremely useful in your Web application. These include custom sorting, item selection, dynamic versus manual column binding, template columns, custom data formatting and data paging. By studying each of these features a DataGrid can be created that's both functional and user-friendly.

Custom Sorting
Say, at one point or another, you wanted your data grid to be sortable. Well, notice a boolean property on the DataGrid called "AllowSorting." Set this to true and you'll see that the column headers on your data grid become clickable- indicating that the grid is now sortable. However, that's only the beginning.

While it would be nice to have the DataGrid sort automatically when setting "AllowSorting" to true, that would limit functionality in some cases. Perhaps you want some custom sorting method to take effect. To do that, DataGrid provides you with an action to overload called "SortCommand." In the properties events for your DataGrid, select the "SortCommand" action and implement it with the method name of your choice.

Your method declaration will look something like this:

private void OnMyGridSort(object source, System.Web.UI.WebControls.DataGridSortCommandEventArgs e)

When one of the column headers is clicked, the "SortCommand" event (and consequently this method) is fired. The e argument (of type DataGridSortCommandEventArs) has a property called "e.SortExpression" that will contain the name of the column the user clicked on. Now it's up to you to use that column name to sort the data accordingly. If you're binding to a data table, consider using the "SortExpression" property in the default views sort property. If you're binding to a class, you may want to implement your own IComparer. Or sort the data whichever way fits your application best. After sorting, re-bind the data to the grid and you're off and running.

Item Selection
Often you'll display a list of items in a data grid and you'll want to let the user select a given row. The DataGrid provides you with a number of ways to select a row to perform some action on the data. The most common is a Button column. To add a button column to your DataGrid, edit the Columns collection property and add the button column that makes the most sense. Each of the buttons will fire the ItemCommand action, but some of them will also fire other events (i.e., Edit will fire ItemCommand first, followed by EditCommand as well).

After adding your button, go to the actions of the DataGrid and add a method for the desired action. For example, enter a method name in the ItemCommand action row. Press the enter key and the method will be automatically generated. You can now use the "e.Item.ItemIndex" property to determine which row had the action performed on it as well as the "e.CommandName" property to find out what the action was (delete, select, edit, etc.).

Now that you know the item the user clicked and the action taken, you have all the information required to perform whatever action you intended.

Dynamic versus Manual Column Binding
By default, the DataGrid is set up to create columns for each row dynamically based on what exists in the data source you have bound it to. This may or may not be what you want in the end.

For example, let's say you data bind a grid to a standard data table read from a database. Perhaps your table contains an ID column or some other column that's necessary, but meaningless to an end user. You really want to hide the ID column and display all the other values. The question becomes, "How do I hide a column in a dynamically data-bound DataGrid?"

First, you go back to the actions of the DataGrid in the properties->events window. Enter a method name for the behavior "ItemCreated." Within that method, you can access the e variable (of type DataGridEventItemArgs) and use the following line to hide a given column:

e.Item.Cells[myColumnIndex].Visible = false;

The variable myColumnIndex indicates the index of the column you want to hide. Run your application and you'll see that the specified column is no longer visible in the grid.

That's fine and dandy, but what if there are a large number of cells you want to hide and only a few you want to keep? It seems counter-productive to create all these cells only to make them invisible. That's when you need to decide whether to use dynamic or manual data binding. Like I said, by default, the DataGrid is set up to generate the columns dynamically. To turn this off, you need to edit the properties of the DataGrid, click on the Columns collection property and uncheck the "Create columns automatically at run time" checkbox.

This will tell the DataGrid to use only the columns specified in this properties window. You can then add the columns you need by adding a Bound Column to the DataGrid for each column you want to display. Add a bound column to the DataGrid to see the options available to you. You'll notice that there are a number of formatting options. Make sure you put the name of the column (or property if data binding to a class) in the "Data Field" field.

Now you can let your DataGrid be data-bound to large datasets and force it to show only a certain number of columns. This is also a useful way to sort the columns in any order you wish. The property page for the Columns property of the DataGrid has an easy way to move columns forward or backward in the list order by using the arrow buttons to move the columns around. Getting the columns to display in the order you intend via dynamic data binding can sometimes be very painful but here it's pretty straightforward.

Custom Data Formatting
In the section above, you may have also noticed a "Data formatting expression" field in the Columns property page of the DataGrid. This field takes a standard formatting string of the string.Format variety to apply to the data in that column. For example, let's say you have a currency field in the data source that you're binding to your data grid. This field is most likely a double or an int and not a full-fledged currency string. So, in the "Data formatting expression" field for that column, enter the string {0:C} (notice the lack of quotation marks). This will format the field to a currency string and display the field correspondingly.

Another nice thing about the DataGrid is that any field with HTML tags will render them automatically. This comes in handy when using the data-formatting expression field as well. Let's say you have a column in your data source that contains URLs to images and that you want to display the images in your DataGrid as images as in Figure 1.

Rather than creating some method that will convert those URLs to

HTML image tags, you can simply enter the data formatting expression <img src="{0}"> (See Figure 2).

It will automatically add the HTML tags around the desired field and, when data-bound, the DataGrid will display the image you need. When data binding the DataGrid will automatically detect that the data in that column contains HTML tags and will render them as such.

Template Columns
Template columns are useful tools where you can put different controls (checkboxes, text boxes, etc.) inside your DataGrid. They let you have user input in your grid and facilitate editing data.

To add a template column to your grid, again edit the Columns collection property of the DataGrid. Add a Template Column. Here you can specify header text and some other limited options. The real magic comes after you press OK.

Close the columns property page and right-click your DataGrid on your form. You'll notice a pop-out menu on the dropdown menu that reads "Edit Template." This will pop out another menu item for each template column you have in your DataGrid. Select your template column from the menu to begin editing.

You'll see your DataGrid convert to a Template Editing control as seen in Figure 3.

The header template and the footer template are self-explanatory. They appear in the column header and footer. The other two items in the control are what we're really concerned about. Whatever you put in the ItemTemplate cell is what will appear in the column when the cell is not in edit mode. It would make sense then that whatever we put in the EditItemTemplate cell is what will appear in the column when the cell is in edit mode. For example, we'll make a text column that's editable. We'll have a column that has an edit/update/cancel option that will toggle the cells on that column from read-only Labels to editable TextBoxes.

First we need to bind our grid to a data source. Let's write a simple data-bind method that will bind the grid to an ArrayList of a simple class. You can bind to any data source you want to for your example, but my code is below.

I'm going to create a simple class with two variables (x and y). The x variable's property (sX) is read/write so that will be the variable that we'll attempt to edit in our DataGrid. See Figure 4 for MyClass Code. Now I've added a BindGrid() method to my WebForm. See the code for that method in Figure 5.

You'll notice that the code is fairly simple. It builds an ArrayList by calling MyClass's constructor 14 times and stores the data in the session. The ArrayList is stored in the session because we need to have semi-permanent storage for our data to update it. If we didn't store the data in the session and simply created the ArrayList each time, then we would have no place to save the data once the user updates the grid.

You'll want to call BindGrid from your Page_Load method. Make sure that you put a check for if(!IsPostBack) before you call it. Otherwise, your grid changes won't be recorded because the grid will always re-bind with the same data.

Now that our grid is data-bound, put a Label in the ItemTemplate cell and a TextBox in the EditItemTemplate cell. Next, if you haven't done so already via the previous sections, put an "Edit, Update, Cancel" column in your DataGrid. Do it by editing the Columns collection of the DataGrid and adding a Button Column of type "Edit, Update, Cancel." You then need to add methods to catch the EditCommand, UpdateCommand and the CancelCommand actions for your DataGrid. Edit the actions under Properties->Events for your DataGrid and enter a method name for each of those items.

Now look at the HTML for your webform. Make sure that the TextBox in your EditItemTemplate has an ID and a Runat="Server" tag. You can bind your Label to your data source with the following code:

<ItemTemplate>
<asp:Label id="Label1" runat="server">
<%# DataBinder.Eval(Container.DataItem, "sX") %>
</asp:Label>
</ItemTemplate>

You will also want to data bind the TextBox in the EditItemTemplate. If you don't then when you click the Edit button on a row, the text that was listed in the read-only label won't be displayed in the corresponding TextBox and the TextBox will be blank. The code for the EditItemTemplate data bind needs to be slightly different than the code above:

<EditItemTemplate>
<asp:TextBox id="MyTextBox" runat="server"
Text='<%# DataBinder.Eval(Container.DataItem, "sX") %>'>
</asp:TextBox>
</EditItemTemplate>

Notice that you have to place the data-bind code inside the Text field of the TextBox tag. Now we need to capture each of the actions for Edit, Update, and Cancel. First let's look at Edit. The code to put the grid in edit mode is rather simple:

NewGrid.EditItemIndex = e.Item.ItemIndex;
BindGrid();

First you specify which row is being edited (EditItemIndex) by setting it equal to the ItemIndex specified in the method argument e (DataGridCommandEventArgs). Then you re-bind the DataGrid by calling the method we created.

Next, let's look at the Cancel method. As you might have guessed, the code for canceling and edit will be similar to initializing an edit:

NewGrid.EditItemIndex = -1;
BindGrid();

First you simply set the EditItemIndex to -1 and then re-bind the grid.

Finally, let's look at the Update method. You need to be able to read the text from the textbox in the EditItemTemplate and then update the data source accordingly. This is why we put our ArrayList in the session. We update the ArrayList in the session with the data read from the TextBox and then we have a semi-persistent data source we can read and write to. The code looks like this:

ArrayList MyList = (ArrayList)Session["MyData"];

TextBox tbUpdate = (TextBox)e.Item.FindControl("MyTextBox");
((MyClass)MyList[e.Item.ItemIndex]).sX = tbUpdate.Text;

Session["MyData"] = MyList;

NewGrid.EditItemIndex = -1;
BindGrid();

First we grab the ArrayList from the session. Then we grab the text from the TextBox by using the FindControl method on the Item property of the e parameter in the update method (DataGridCommandEventArgs). Then we replace the session variable with our newly updated ArrayList, set the EditItemIndex to -1 (completing the update) and then re-bind the DataGrid. Because we've updated the ArrayList in the session, when we re-bind to the data source, it will reflect the user's changes.

Now you're ready to Edit, Update and Cancel to your heart's content. Run your application and notice how clicking Edit replaces the Label with a TextBox. Pressing Cancel then simply changes it back, while pressing Update will change it back but not before updating the data with whatever text you've put in your TextBox.

Paging
The last thing we'll discuss here is paging for DataGrids. Paging lets you show a maximum number of records per page and provides you with ways to go to previous and next pages. Implementing the built-in paging for the DataGrid is simple.

Edit the properties of your DataGrid and scroll down to the Paging section. Set "AllowPaging" to true and set the "PageSize" to the maximum number of records you want per page. If you use the example from the previous section, 10 is a good number since there are 14 records total. Next you need to provide a method for the PageIndexChanged action for your DataGrid. Edit the Properties->Events for your DataGrid and enter a method name for the PageIndexChanged method.

Now we simply need to update the current page index in our DataGrid and re-bind the data:

NewGrid.CurrentPageIndex = e.NewPageIndex;
BindGrid();

Now run your application; you can scroll back through records and forth with ease.

This built-in method of paging is nice and convenient for small applications. The drawback is that you have to load the entire dataset into your data source to make it work. Obviously if you are working on a very large dataset, it won't be very efficient. .NET does provide some custom paging options (that you may have noticed in the Paging properties of your DataGrid) which will let you page your data on your own to get around this issue.

Hopefully, if you've been turned off the DataGrid (as I once was) because of its lack of features, you can see that there are actually a variety of things you can do with the .NET DataGrid that provide a good amount of flexibility and functionality with minimal effort on your part. By digging a little deeper into the DataGrid's less-documented features we can uncover a great tool for displaying and manipulating data in a user-friendly way.

About Aaron Reed
Aaron Reed is an assistant professor specializing in software architecture and design and .NET development at Neumont University in Salt Lake City, UT. He has worked professionally in the industry for over 12 years as a lead architect/designer, development manager, and VP of development. When he isn't spending time reading up on the latest in software development, Aaron loves spending time with his beautiful wife and three children.

YOUR FEEDBACK
John Portnov wrote: This code does not work for me. I created a new website and a C# console application in VS.NET 2005. HttpWebResponse res = (HttpWebResponse)req.GetResponse(); throws a 500 error. Also, viewstate = HttpUtility.UrlEncode(viewstate); should be viewstate = HttpUtility.UrlDecode(viewstate); Can you please test your code and provide me with working code and/or advise how to make it work? Thanks in advance, p
MICROSOFT .NET LATEST STORIES
We are seeing more being written about Cloud computing and cloud platforms today, and there is strong validation that the future of computing will include significant innovation and value in web/cloud platforms. Microsoft’s Cloud strategy is materializing, and as part of our overall ...
Nth Penguin has released WW.DataServices to the public and is available for immediate download at: www.nthpenguin.com. WW.DataServices, the first system of the WebWidgetry engine, removes all the work from accessing your data. You simply point it to a database location, push a button,...
Gizmox announced the release of a fully functional beta version of its Visual WebGui (VWG) with support for Microsoft Silverlight. For the first time, VWG enables Silverlight for enterprise applications by providing a RAD like Windows Forms development experience with drag & drop desig...
Google will come out from behind the Firefox browser that it’s been pumping money into – and profiting royally from – and take direct aim at Microsoft with a browser of its very own. The widgetry is called Google Chrome and Google Chrome, like all of Google’s non-search widgetr...
Many of today (and tomorrow’s) development projects lend themselves nicely to RIA application patterns. Silverlight offers a compelling RIA development experience that works on Linux, the Mac and windows as well as all major browsers. With HD video, vector based graphics and a rich s...
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON FEATURED WHITEPAPERS

ADS BY GOOGLE
BREAKING NEWS FROM THE WIRES
DataCore Software, the leading provider of storage virtualization software, joins Microsoft's "Get V...