DataGridHelper tool






4.71/5 (25 votes)
A utility class to ease adding CSS classes and confirmation dialogs to the ASP.NET DataGrid component.
- Download demo web project - 35.7 Kb
- Download source - 2.74 Kb (just the
DataGridHelper
class) - Download installer - 3.88 Kb (installs
DataGridHelper
class as a HttpModule in a web application)
Introduction
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 DataGrid
s 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.
DataGridHelper
can:
- 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). - add a JavaScript confirmation dialog to the buttons in a column of a
DataGrid
(one line of code).
V. 1.2 - IHttpModule implementation
For those of you who want to add CSS classes to your DataGrid
s without even a single line of code, the DataGridHelper
class now implements the IHttpModule
interface. This makes it possible to have all DataGrid
s 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 DataGrid
.
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 DataGrid
.
I tried enumerating through the DataGrid.Items
, but that only gives access to the Item
, AlternatingItem
, SelectedItem
and EditItem
items.
Here are the core methods:
//Adds CSS class names to cells, rows and buttons in a datagrid
public static void AddCssToDataGrid(DataGrid aGrid); //(updated in version 1.1)
//Adds an attribute to all cells in a DataGrid
public static void AddAttributesToCells(DataGrid theGrid,
string attributeKey, string attributeValue);
//Adds an attribute to all rows in a DataGrid
public static void AddAttributesToRows(DataGrid theGrid,
string attributeKey, string attributeValue);
//Adds a confirm javascript dialog to the buttons in a column of a DataGrid
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.
- Events
- If "Delete" was clicked - delete that row.
- If "Load data" was clicked - reload the data.
PreRender
- 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. - I have an external JavaScript file "scripts.js" with a little DHTML script that dynamically changes the CSS classes of HTML objects, so they present themselves differently visually, depending on their class.
- 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
DataSet
'sWriteXml()
method. This way I can (and do) reload the data into theDataSet
using theReadXml()
method. - I have a
DataGrid
nameddgPersons
on the page. Using the Property Builder in Visual Studio, I have added a hidden first column (column 0) to thisDataGrid
containing the primary key of the rows in theDataTable
. This way I can easily look up the corresponding row in theDataTable
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:
//the dataset containing the table with our persons
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)
{
//load the data to display
LoadData();
}
LoadData() method
Here is the LoadData
method that is called from Page_Load
:
public void LoadData()
{
//if we don't have any data in Session state
if(Session["persons"] == null)
{
//find the full path to the xml file
string path = Server.MapPath("persons.xml");
//create a new, empty dataset
persons = new dsPersons();
//fill it with data from the file
persons.ReadXml(path);
//save it in Session state
Session["persons"] = persons;
}
//in all cases, we can now retrieve
//the dataset from Session state
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 DataTable
:
Delete event finds and removes a person:
private void dgPersons_DeleteCommand(object source,
System.Web.UI.WebControls.DataGridCommandEventArgs e)
{
//we find the id of this row
//by looking in the hidden first colum
int id = int.Parse(e.Item.Cells[0].Text);
//this person we look up in the Table,
//and mark the row for deletion
persons.person.FindByid(id).Delete();
}
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)
{
//empties the Session state of data
Session["persons"] = null;
//reloads the dataset from disk
LoadData();
}
In any case - the PreRender
event happens last, and this is the place where my utility class gets to work:
PreRender displays the data:
// This method runs right before the page
// and all its controls are converted to HTML
// and sent to the client's browser.
// This is the place to databind,
// and therefore we do all the adding of
// attributes, etc. here.
private void WebForm1_PreRender(object sender, System.EventArgs e)
{
//if the checkbox is checked
//then we add CSS class names
//so the CSS file's contents get to work
if (chkAddCSS.Checked)
DataGridHelper.AddCssToDataGrid(dgPersons);
//set the datagrid's datasource to the
//table containing our people
dgPersons.DataSource = persons.person;
//bind the data
dgPersons.DataBind();
//if the user wants to add deleteconfirmation
if(chkAddDeleteConfirmation.Checked)
{
//then we add a confirmation dialog to the
//linkbutton in row 3.
//Remember that we've hidden row zero
//that's why the Delete row is number three.
DataGridHelper.AddConfirm(dgPersons, 3,
"Do you wish to delete this person?");
}
//if the user wants to add mouseovers
if(chkAddJavascriptMouseovers.Checked)
{
//add the mouseover and mouseout attributes
//and link them to to the javascript
//function "changeStyle()"
DataGridHelper.AddAttributesToCells(dgPersons,
"onmouseover", "changeStyle(event);");
DataGridHelper.AddAttributesToCells(dgPersons,
"onmouseout", "changeStyle(event);");
//using the event to make the javascript cross-browser
//you can add any code you like with
//the "AddAttributesToCells" method.
}
//make sure all columns in the DataGrid
//are one third of the width
DataGridHelper.AddAttributesToCells(dgPersons,"width", "33%");
}
Points of Interest
The JavaScript
You can use any of your own or other people's JavaScript code along with the DataGridHelper
class. I've just included one of my more interesting JavaScript codes here, in case you could use the same functionality at some point in life. I switch the CSS class name of the cells in the table when the mouse moves over them.
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.
<script language="javascript">
//////////////////////////////////////////////////
// CHANGESTYLE - by Jakob Lund Krarup //
//////////////////////////////////////////////////
/*This method will change the CSS class name
of an HTML item.
The name gets the text "_hover" appended
when the mouse moves over the item,
and the name has the text "_hover" removed
from the class name when the mouse moves out again.
CROSSBROWSER:
Made this work with FireFox after reading:
http://www.oreillynet.com/pub/a/javascript/synd/2001/09/25/event_models.html?page=2
*/
function changeStyle(evt)
{
//Crossbrowser - get the event as a parameter (FireFox)
//or as the windows event (IE)
var theEvent = evt || window.event;
//Crossbrowser - get the HTML element that fired this event
//as either target (FireFox) or srcElement (IE)
var theEventSource = theEvent.target || theEvent.srcElement;
//according to the event type
//...switch the CSS class of the element
switch(theEvent.type)
{
//if the event that invoked this method
//was a mouseover event
case "mouseover" :
//then we add "_hover" to the class name
theEventSource.className += "_hover";
break;
//otherwise - if this was a mouseout event...
case "mouseout" :
//then we remove the "_hover" from the class name
theEventSource.className =
theEventSource.className.replace("_hover", "");
}
}
</script>
This allows us to define CSS classes like this, that work with the cells of DataGrid
:
.Item_cell {
background-color: Cornflowerblue;}
.Item_cell_hover {
background-color: red;
font-weight:bold;
color: White;}
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:
web.config addition
<httpModules>
<add name="DataGridHelperModule"
type="AddCssToDataGridSample.DataGridHelper, HttpModuleDataGridHelper" />
</httpModules>
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.)
Ending note
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).
History
- 1.2
- Added implementation of the
IHttpModule
interface to theDataGridHelper
class. So in addition to working as before, you can now have the CSS classes added with no code : )
- Added implementation of the
- 1.1
- As suggested by R.vd.B - I've changed the
AddCssToDataGrid
so it also adds CSS classes to the buttons in theDataGrid
. - 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
DataGridHelper
class, but was a lack of cross-browser programming in the sample JavaScript I used. - The script has been updated to work cross-browser now : ).
- Thanks Scott (and SirTrolle who made the connection to the CSS)! : )
- As suggested by R.vd.B - I've changed the