Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

DataGridHelper tool

0.00/5 (No votes)
21 Jul 2005 1  
A utility class to ease adding CSS classes and confirmation dialogs to the ASP.NET DataGrid component.

Try it online

Sample image of the tool in action

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 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.

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 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 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's WriteXml() method. This way I can (and do) reload the data into the DataSet using the ReadXml() method.
  • I have a DataGrid named 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:

//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 the DataGridHelper class. So in addition to working as before, you can now have the CSS classes added with no code : )
  • 1.1
    • As suggested by R.vd.B - I've changed the AddCssToDataGrid so it also adds CSS classes to the buttons in the DataGrid.
    • 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)! : )

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here