My ASP knowledge base

The grid class itself

<< Previous page Next Page >>

The grid class is the largest class, but quite easy to understand. The code you will find below. A few remarks:

[Designer(typeof(WITGridDesigner))]
Links the designer class WITGridDesigner to the WITGrid-class. When you edit a web page in VS2005 in design view (in stead of source view), you want to see information about the control. The designer handles this information. This designer class will be explained later on.

CompositeDataBoundControl
The control is derived from the CompositeDataBoundControl which already handles a few things, like DataSourceID.

CreateChildControls
This is the largest function of the grid class. This function build the grid control (table). I haven’t used ViewState/IStateManager so the grid is build again after a PostBack event.

Handling custom events
The grid has two custom events:

  • RowCommand - the user clicked a row, edit, delete or order button. This event enables the user to handle the related command actions.
  • RowDataBound – triggered each time when a new row is ready to be added to the control. This enables the user to change the final information displayed.

The following steps are taken to define the custom events:

Add the IPostBackEventHandler-interface to the grid
This interface has RaisePostBackEvent as a member, which enables the grid to process an event raised when a form is posted to the server.

Define the event handlers
public event EventHandler<WITGridRowCommandEventsArgs> RowCommand;
public event EventHandler<WITGridRowEventArgs> RowDataBound;

The events have custom arguments. These will be explained in the next article.

Add the onclick scripts
When the grid’s rows and (image) buttons are defined, a ‘onclick’ attribute is added with related client script.
tr.Attributes["onclick"] = “javascript:” + this.Page.ClientScript.GetPostBackEventReference(this, rowData);
The rowData parameter contains information about the command, row and id. This information is processed in ‘RaisePostBackEvent’

Define ‘RaisePostBackEvent’
This event handler has one argument (eventArgument) which contains the data given in the GetPostBackEventReference that triggered the event. In case of the grid this is the rowData which contains the command name, row number and record key. This information is put into the WITGridRowCommandEventsArgs and the custom event is triggered.

Trigger RowDataBound per row
Instead of adding each row directly to the table, the new row is created in the custom WITGridRow class. After the row is defined, this class is used in triggering the RowDataBound-event. This enables the programmer to read the newly created row information and make changes to it in the web page’s code behind. After the RowDataBound-event, the WITGridRow-information is added to the grid’s table

using System;
using System.Data;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;

namespace WITControlsLibrary
{
    [Designer(typeof(WITGridDesigner))]
    [ParseChildren(true, "GridFields")]
    public class WITGrid : CompositeDataBoundControl, IPostBackEventHandler
    {
        #region private data
        //—————————–  Private data ————————————–//
        private Collection<GridField> _gridFields;  //Inner elements
        private bool _highLightSelectedRow;     //If the row should be highlighted
        private string _dataKeyName = “”;       //The field name containing the key
        private bool _showEditColumn = false;  //Up and down icon
        private bool _showOrderColumn = false;  //Up and down icon
        private bool _showDeleteColumn = false; //Delete icon
        private string _noRecordsText = “No records where found.”;  //Text displayed when no records where found
        private string _confirmDeleteText = “This record and all related data will be deleted. Continue?”;
        #endregion

        #region Events
        //—————————–  Events ————————————–//
        public event EventHandler<WITGridRowCommandEventsArgs> RowCommand;
        public event EventHandler<WITGridRowEventArgs> RowDataBound;
        #endregion

        #region Properties
        //—————————–  Properties ————————————–//

        //A collection of the inner elements (BoundField, CheckBoxField, etc)
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [ReadOnly(true)]
        public Collection<GridField> GridFields
        {
            get
            {
                if (_gridFields == null)
                    _gridFields = new Collection<GridField>();
                return _gridFields;
            }
        }
       
        //Highlight the selected row (hovering over it with the mouse pointer)
        [Category("Appearance")]
        [Description("Highlight the row")]
        public bool HighLightSelectedRow
        {
            get { return _highLightSelectedRow; }
            set { _highLightSelectedRow = value; }
        }

        // The name of the data field containg the key.This key will be returned in the RowCommand-event
        [Category("Data")]
        [Description("The data field containg the key")]
        [DesignOnly(true)]
        public string DataKeyName
        { set { _dataKeyName = value; } }

        //Show the edit column
        [Category("Data")]
        [Description("Show the edit column")]
        public bool ShowEditColumn
        { get { return _showEditColumn; } set { _showEditColumn = value; } }

        //Show the order column
        [Category("Data")]
        [Description("Show the order column")]
        public bool ShowOrderColumn
        { get { return _showOrderColumn; } set { _showOrderColumn = value; } }

        //Show the delete column
        [Category("Data")]
        [Description("Show the delete column")]
        public bool ShowDeleteColumn
        { get { return _showDeleteColumn; }  set { _showDeleteColumn = value; } }

        //The text displayed when no records are available
        [Category("Appearance")]
        [Description("The text displayed when no records are available")]
        public string NoRecordsText
        { get { return _noRecordsText; } set { _noRecordsText = value; } }

        //The text displayed asking the user for confirmation (delete action)
        [Category("Appearance")]
        [Description("The text displayed when asking the user to confirm the deletion of a record.")]
        public string ConfirmDeleteText
        { get { return _confirmDeleteText; } set { _confirmDeleteText = value; } }
        #endregion

        #region local events
        //—————————–  Local Events ————————————–//

        //Build the grid
        protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
        {
            //The IStateManager is not used, therefor the grid has to be
            //build again in case of a PostBack (therefor the dataBinding property
            //is not checked)
           
            //Disbale viewstate, otherwise the datasource/binding is lost after a
            //postback and I have not implemented the viewstate (alle element  are lost)
            this.EnableViewState = false; 

            int count = 0;  //Count the controls (return value)

            if (dataSource == null)
            {
                //No records found
                Label lb = new Label();
                lb.Text = _noRecordsText;
                lb.CssClass = “gridview-empty”;
                Controls.Add(lb);
                count++;
            }
            else
            {
                //Records were found, build the grid
                Table tb = new Table();
                tb.CellPadding = 0;
                tb.CellSpacing = 0;
                if (!String.IsNullOrEmpty(CssClass)) tb.CssClass = CssClass;

                //Build header ———————————————————–
                TableHeaderRow thr = new TableHeaderRow();
                thr.TableSection = TableRowSection.TableHeader;
                TableHeaderCell thc;

                foreach (GridField gf in _gridFields)
                {
                    //A header cell for each field
                    thc = new TableHeaderCell();
                    if (gf.CssClass != null) thc.CssClass = gf.CssClass;
                    thc.Attributes["scope"] = “col”;
                    if (gf.HeaderText != null) thc.Text = gf.HeaderText;
                    thr.Cells.Add(thc);
                }

                //Special columns
                if (_showDeleteColumn)
                {
                    thc = new TableHeaderCell();
                    thc.Text = “Delete”;
                    thc.Style["text-align"] = “center”;
                    thr.Cells.Add(thc);
                }

                if (_showEditColumn)
                {
                    thc = new TableHeaderCell();
                    thc.Text = “Edit”;
                    thc.Style["text-align"] = “center”;
                    thr.Cells.Add(thc);
                }

                if (_showOrderColumn)
                {
                    thc = new TableHeaderCell();
                    thc.Text = “Order”;
                    thc.Style["text-align"] = “center”;
                    thr.Cells.Add(thc);
                }

                tb.Rows.Add(thr);

                //Body ———————————————————————–
                TableRow tr;
                TableCell tc;
                Image img;
                string rowData = “”;
                string rowCancel = “”;  //cancel row action (delete)

                //Build each new row in WITGridRow (instead of directly adding it
                //to the table’s row). Trigger the event RowDataBound to enable
                //the programmer to change or read the information before the grid is build.
                //Then build the grid.
                   
                int row = 0;
                foreach (DataRowView dataitem in dataSource)
                {
                    //New custom row for RowDataBound-event
                    WITGridRow  wgr = new WITGridRow(dataitem, row);

                    //Build per (data)row
                   
                        tr = new TableRow();
                        tr.TableSection = TableRowSection.TableBody;
                        if (_highLightSelectedRow)
                        {
                            tr.Attributes["onmouseover"] = “this.className=’gridview-highlight’;”;
                            tr.Attributes["onmouseout"] = “this.className=””;
                            rowData = “row_” + row.ToString();
                            if (_dataKeyName != “”) rowData += “_” + dataitem[_dataKeyName].ToString();
                            tr.Attributes["onclick"] = “javascript:” + this.Page.ClientScript.GetPostBackEventReference(this, rowData);
                        }

                        //Regular items
                        foreach (GridField gf in _gridFields)
                        {
                            //Build per column (data field)
                            tc = new TableCell();
                            count++;
                            tc.CssClass = gf.CssClass;

                            if (gf is CheckBoxField)  //Put checkbox before bound because checkbox is bound
                            {
                                CheckBoxField cbf = (CheckBoxField)gf;
                                if (cbf.DataField == null) throw (new NullReferenceException(“The data field for ‘” + cbf.ID + “‘ is not defined.”));
                                CheckBox cb = new CheckBox();
                                cb.Enabled = false;
                                cb.Checked = Convert.ToBoolean(((DataRowView)dataitem).Row[cbf.DataField]);
                                cb.CssClass = “formcheckbox”;
                                cb.ID = cbf.ID;
                                cb.Text = “”;
                                tc.Style["text-align"] = “center”;
                                tb.EnableViewState = false;
                                tc.Controls.Add(cb);
                            }else if (gf is BoundField)
                            {
                                BoundField bf = (BoundField)gf;
                                if (bf.DataField == null) throw (new NullReferenceException(“The data field for ‘” + bf.ID + “‘ is not defined.”));
                                tc.ID = gf.ID;
                                tc.Text = ((DataRowView)dataitem).Row[bf.DataField].ToString();
                            }
                            else if (gf is TemplateField)
                            {    //<< to do: not yet implemented
                            }
                            wgr.Cells.Add(tc);
                        }

                        //Special columns

                        if (_showDeleteColumn)
                        {
                            tc = new TableCell();
                            count++;
                            tc.Width = 50;
                            tc.Style["text-align"] = “center”;
                            img = new Image();
                            img.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), “WITControlsLibrary.Resources.delete.gif”);
                            rowData = “delete_” + row.ToString();
                            rowCancel = “cancel_” + row.ToString();  //to avoid a row click when the user cancels the delete
                            if (_dataKeyName != “”) rowData += “_” + dataitem[_dataKeyName].ToString();
                            img.Attributes["onclick"] = “javascript:if (confirm(‘” + _confirmDeleteText + “‘)) { “ + this.Page.ClientScript.GetPostBackEventReference(this, rowData) + ” } “ +
                                                                    ” else “ + this.Page.ClientScript.GetPostBackEventReference(this, rowCancel);
                            tc.Controls.Add(img);
                            wgr.Cells.Add(tc);
                        }

                        if (_showEditColumn)
                        {
                            tc = new TableCell();
                            count++;
                            tc.Width = 30;
                            tc.Style["text-align"] = “center”;
                            img = new Image();
                            img.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), “WITControlsLibrary.Resources.pencil.gif”);
                            rowData = “edit_” + row.ToString();
                            if (_dataKeyName != “”) rowData += “_” + dataitem[_dataKeyName].ToString();
                            img.Attributes["onclick"] = “javascript:” + this.Page.ClientScript.GetPostBackEventReference(this, rowData);
                            tc.Controls.Add(img);
                            wgr.Cells.Add(tc);
                           
                        }

                        if (_showOrderColumn)
                        {
                            //Up
                            tc = new TableCell();
                            count++;
                            tc.Width = 60;
                            tc.Style["text-align"] = “center”;
                            img = new Image();
                            img.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), “WITControlsLibrary.Resources.up.gif”);
                            rowData = “up_” + row.ToString();
                            if (_dataKeyName != “”) rowData += “_” + dataitem[_dataKeyName].ToString();
                            img.Attributes["onclick"] = “javascript:” + this.Page.ClientScript.GetPostBackEventReference(this, rowData);
                            tc.Controls.Add(img);
                            wgr.Cells.Add(tc);

                            //Down
                            img = new Image();
                            img.ImageUrl = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), “WITControlsLibrary.Resources.down.gif”);
                            rowData = “down_” + row.ToString();
                            if (_dataKeyName != “”) rowData += “_” + dataitem[_dataKeyName].ToString();
                            img.Attributes["onclick"] = “javascript:” + this.Page.ClientScript.GetPostBackEventReference(this, rowData);
                            tc.Controls.Add(img);
                            wgr.Cells.Add(tc);
                        }
                       
                       
                        //Trigger OnRowDataBound
                        if (RowDataBound != null)
                        {
                            //RowDataBound(this, new GridViewRowEventArgs(gvr));
                            RowDataBound(this, new WITGridRowEventArgs(wgr));
                        }

                        //Add the (changed) information to the table.
                        while (wgr.Cells.Count > 0)
                        {
                            //Adding the cell will empty the cell collection
                            tr.Cells.Add(wgr.Cells[0]);
                        }
                        tb.Rows.Add(tr);

                   
                    row++;
                   
                }  
                Controls.Add(tb);
            }
            return count;
        }

        public void RaisePostBackEvent(String eventArgument)
        {
            //Handle the raised postback and determine what command (icon) was clicked

            int row = -1;
            string key = “”;
            string command = “”;

            //Get command
            int pos = eventArgument.IndexOf(“_”);
            command = eventArgument.Substring(0, pos);

            if (command.ToLower() != “cancel”)
            {
                //Get row and key
                string temp = eventArgument.Substring(pos + 1);
                pos = temp.IndexOf(“_”);
                if (pos > 0)
                {
                    row = Convert.ToInt32(temp.Substring(0, pos));
                    key = temp.Substring(pos + 1);
                }
                else
                    row = Convert.ToInt32(temp);

                EventHandler<WITGridRowCommandEventsArgs> tempEvent = this.RowCommand;
                if (tempEvent != null)
                    tempEvent(this, new WITGridRowCommandEventsArgs(row, key, command));
            }
        }

        #endregion

    }
}

<< Previous page Next Page >>

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>