Try it online
When using Visual Studio .NET to create ASP.NET pages, the Property Builder is a great tool for quickly customizing the functionality or coloring of the ASP.NET
DataGrid control on a single page. However, I've sorely missed the ability to add CSS class names to the different element types (Header, Footer, Item, AlternatingItem, etc.) programmatically, so I could alter the look of all
DataGrids in my solution's pages from a single CSS file. I've looked around on the web for a solution, but since I didn't find any - I've created my own. This little utility class also has a few other tricks up its sleeve.
- add CSS class names to all rows, cells and buttons in a
DataGrid. E.g. "Item_row", "Header_cell", "Button_Update", etc. (one line of code).
- add attributes to all rows and/or cells in a
DataGrid (one line of code).
DataGrid (one line of code).
V. 1.2 - IHttpModule implementation
For those of you who want to add CSS classes to your
DataGrids without even a single line of code, the
DataGridHelper class now implements the
IHttpModule interface. This makes it possible to have all
DataGrids automatically get the CSS classes added in your entire solution (by editing the web.config file) or in all solutions on the server (by editing the machine.config file).
See how to do this [here].
Using the code
I've created a little web project to show you how to use this utility class. Most of the methods are pretty straightforward, but adding CSS to the
DataGrid has a little catch: you have to call this method before databinding the
The reason for this is that I haven't been able to find a way of getting to the Header, Footer, Pager, etc. rows in the
DataGrid in any other way than by attaching to the
ItemDataBound event of the
I tried enumerating through the
DataGrid.Items, but that only gives access to the
Here are the core methods:
public static void AddCssToDataGrid(DataGrid aGrid);
public static void AddAttributesToCells(DataGrid theGrid,
string attributeKey, string attributeValue);
public static void AddAttributesToRows(DataGrid theGrid,
string attributeKey, string attributeValue);
public static void AddConfirm(DataGrid theGrid,
int columnNumber, string question);
The sample project I've included follows the traditional pattern of many web projects:
Page_Load - Check to see if we have data in Session.
- If not - load it from disk into session.
- If "Delete" was clicked - delete that row.
- If "Load data" was clicked - reload the data.
- Databind and make last minute modifications.
For those of you unfamiliar with this approach, it will help you to know that ASP.NET pages are always processed in the same order.
Page_Load goes first, which means that this is a good place to make sure that data is loaded.
- All events are processed next, this includes all postback events (button clicks, etc.) and is the time to delete, edit and add stuff.
PreRender runs last, and this is the time to present the data in its current state. In other words "databind".
To put this in another way: "Load data" - "Edit data" - "Show data".
The entire web project is not much of an application as such. It was solely created to display the
DataGridHelper class' functionality.
Things to note:
- I have an external CSS file "sample.css" with the styles "Item_cell", "AlternatingItem_cell", etc. This automatically colorizes the
DataGrid after the CSS classes have been added to the cells and rows.
- To avoid having to include a database in the sample project, I created a typed dataset, loaded the database table into it, and wrote it to disk using the
WriteXml() method. This way I can (and do) reload the data into the
DataSet using the
- I have a
dgPersons on the page. Using the Property Builder in Visual Studio, I have added a hidden first column (column 0) to this
DataGrid containing the primary key of the rows in the
DataTable. This way I can easily look up the corresponding row in the
DataTable when a user clicks the Delete button in a row.
The sample project's code
DataSet as a member variable
I have declared my typed dataset as a member level variable so I can access it from all methods:
protected dsPersons persons;
Page_Load loads data
All that happens when the page loads is that data is loaded.
private void Page_Load(object sender, System.EventArgs e)
Here is the
LoadData method that is called from
public void LoadData()
if(Session["persons"] == null)
string path = Server.MapPath("persons.xml");
persons = new dsPersons();
Session["persons"] = persons;
persons = (dsPersons) Session["persons"];
...at this point we are sure to have a loaded dataset in the Session, so if this page view was caused by a click on a Delete button, then we can go ahead and mark that row as deleted in the
Delete event finds and removes a person:
private void dgPersons_DeleteCommand(object source,
int id = int.Parse(e.Item.Cells.Text);
If the user didn't click "Delete", but "Reload data", then this event would also occur at this time in the page's lifecycle, and we could load the data anew:
Reload data from file:
private void btnReloadData_Click(object sender, System.EventArgs e)
Session["persons"] = null;
In any case - the
PreRender event happens last, and this is the place where my utility class gets to work:
PreRender displays the data:
private void WebForm1_PreRender(object sender, System.EventArgs e)
dgPersons.DataSource = persons.person;
"Do you wish to delete this person?");
Points of Interest
This is done instead of the altering color, size, etc. directly. By using this approach you are able to revert to the original state of the cell when your mouse leaves it, because I only append and remove the suffix "_hover" to the class name.
Because we have two alternating rowtypes "Item" and "AlternatingItem", we can't just reset the rows' or cells' background color to a predefined color, as this would make the rows appear alike after a mouseout.
Have a look and see if you like it.
Update: This is an improved version that uses cross-browser scripting to access the event model of either IE or FireFox.
var theEvent = evt || window.event;
var theEventSource = theEvent.target || theEvent.srcElement;
case "mouseover" :
theEventSource.className += "_hover";
case "mouseout" :
This allows us to define CSS classes like this, that work with the cells of
Advanced - IHttpModule interface implementation (version 1.2)
This implementation makes it possible for the
DataGridHelper class to attach CSS to all "outgoing"
DataGrid controls in a web project without you having to write code for each of them. If you just want to use the
DataGridHelper class and call the methods when needed, then just skip this last part. To make this work, you have to add the HttpModuleDataGridHelper.dll file to the BIN folder of your web application, and add the following lines to the
</system.web> part of your web.config:
type="AddCssToDataGridSample.DataGridHelper, HttpModuleDataGridHelper" />
In case you don't want to manually edit your web.config, just run this tool in your web application's folder. It will update your web.config file for you, and download the DataGridHelper.dll file from the Internet to the BIN folder. The next article I submit to The Code Project will be about this installer-tool, and how it was made.
(If you want to know more about coding HttpModules, I suggest you read this article.)
I thoroughly enjoy the CodeProject newsletter each week. I am an avid reader and I hope my contribution has given something back to you, the community:)
Before you rush to the keyboard to let me know that I can just add a CSS class to my
DataGrid and then define how the
TD code or
TR code should be styled using the
".datagrid td" code, I just want to let you know that I know ; ).
I just think it is easier to adjust any client scripting, CSS or DHTML if all cells and rows have a CSS class.
Kind regards - Jake (Jakob Lund Krarup).
- Added implementation of the
IHttpModule interface to the
DataGridHelper class. So in addition to working as before, you can now have the CSS classes added with no code : )
- As suggested by R.vd.B - I've changed the
AddCssToDataGrid so it also adds CSS classes to the buttons in the
- Scott (bisc0tti) noticed that when the CSS was added in FireFox, the delete confirmation didn't work. This hasn't got anything to do with the
- The script has been updated to work cross-browser now : ).
- Thanks Scott (and SirTrolle who made the connection to the CSS)! : )