Building Sleek, Soft and Simple DataGrids
Last November Josh Stodola wrote a detailed post discussing how great looking fluid-width rounded corners can easily be created using Paint.NET, a handful of DIV tags and a small amount of CSS. The basic technique Josh outlines isn't new, but he does a great job walking through the steps with just the right amount of detail. I remember reading the article sometime after I struggled through creating an AjaxControlToolkit control based on NiftyCorners (being completely uncreative, I called my custom extender control the NiftyCornersExtender) and I found it very interesting. I recently went back through and re-read Josh's article this past week and went through his tutorial again.
It turns out this was great timing - I am working on a project where the client has requested a sleek, soft and simple interface - those were their exact words. So I used Josh's tutorial to frame a couple of my interface elements with a rounded light blue border. The screen shots of these grids are below, and I am pretty happy with how they turned out (we will see what the client thinks). The grids have that nice professional and polished feel like the ones found on some of the .Net component vendors demo sites AND they are fluid.
Below are the screen shots for the two grids I created. The top one displays the rows in the Northwind products table, 10 rows at a time. It supports paging and sorting. The second grid also displays product data, but only one row at a time. The second one is what I am planning to use for a DetailView.
Markup and Images
CSS doesn't have any built in mechanism for rounding corners, so Josh uses the following markup to build the frame.
<div class="rounded"> <div class="top"><div class="right"></div></div> <div class="middle"><div class="right"> <div class="content"> <!--Content goes here--> </div> </div></div> <div class="bottom"><div class="right"></div></div> </div>
For both the samples above, a ListView control is embedded within the content DIV (where it says 'Content goes here'). The ListView is bound to the products data source and is responsible for create the HTML table for each of the grids.
The CSS for the classes above position the following the images around the border. Again, Josh's tutorial has a great explanation of how to create these images.
A Few Tips
If you download the sample code, you will no doubt notice there isn't too much code for the above examples. Both of the data grids are rendered as HTML tables by the ListView control. Both of these grids support some sort of paging, so a DataPager has been embedded into the ListView's LayoutTemplate. If either of these topics are new to you, feel free to check out my posting archives for both the ListView and DataPager controls to see a few more live samples. Besides that, here is a small collection of subtle tips that maybe aren't so obvious from browsing the code.
1. Sorting with Arrow Icons
To toggle the sorting icons I run a bit of code when the ItemDataBound event fires on the ListView. In this event handler, I use the SortExpression property of the ListView to see what column the grid is being sorted by. Then, I rip through all of the tables header cells and find the one that has a LinkButton with the corresponding SortExpression. After the button is found, I add a sortasc or sortdesc CSS classes to the TH element. By default the anchor rendered by the column header LinkButtons have the no sort applied image applied for its background. If the sorting css classes are applied, this image is replaced by the ascending or descending one.
2. Making the Complete Header Cell Clickable
I find users are most happy when clicking anywhere in the grids header cell sorts the grid. If you look at our grid, the sorting icon is right aligned and the text is left aligned. Some users will naturally click the text to sort, others will click the icons. Either way it would be nice to be a little forgiving so any mouse click within the header cell results in the sort being executed. The easiest way to accomplish this is to set the anchor to render as a block element instead of inline. For the grid above, I have done this using the following CSS rule.
3. Using LINQ to XML to Create a Portable Example
If you have downloaded any of my other examples, you may have noticed that I do what I can to make my examples as portable as possible. Most commonly I do this by using an XML file as my datasource instead of SQL Server. For this sample I exported the Northiwnd Products, Categories and Suppliers tables to an XML file and used LINQ to XML to extract the data and fill my grid. And it was all pretty simple.
To extract the data from the products table I used the FOR XML clause like so ...
select * from dbo.Products product for xml auto
I then saved the resulting XML into a flat file and placed it in the app_data directory. Then I used the LINQ to XML objects to load this data into .Net objects that bind to my ListView. Below is the LINQ query that fills the grids above.
4. Rendering a 4 Column DetailsView using the ListView
Finally, this might seem like a no-brainer, but with the ListView it is really easy to create a DetailsView like presentation with 4 columns instead of the 2. To do this, I bound the following basic template to the ListView for the second grid (the one that displays Products one at a time) - notice each row has two TH elements and two TD elements. I haven't actually used this layout before, but I saw that SalesForce.com does something similar and I liked how it looked. Again, we will see what my client's think.
That's it. Enjoy!