|
YOUR FEEDBACK
|
TOP MICROSOFT .NET LINKS Performance Secrets of the .NET DataGrid
A look under the covers
By: Aaron Reed
Mar. 22, 2005 12:00 AM
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 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 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 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 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 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> 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> 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; 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; 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"]; 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 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; 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. YOUR FEEDBACK
MICROSOFT .NET LATEST STORIES
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK BREAKING NEWS FROM THE WIRES
|
||||||||||||||||||||||||||||||||||||