Building a Full-Featured Custom DataGrid Control

Now We Compile...

Till now, most of the key elements in our DLL have been grappled with. Now we finalize our application by compiling it and then importing it into our page thus rounding off everything full circle.

Anytime you create a class of any kind that requires implementation within your page it first needs to be compiled, and placed into your applications bin, or wwwroot\inetpub\bin folder. Since our classes language is C#, we use the .NET C# compiler from a command line like so, or typed into a .bat batch file (which is included in this article's source code as makedg.bat):

csc /t:library /out:bin\mycustDG.dll mycustDG.cs /optimize

This tells our compiler that we are going to create a DLL named mycustdg using mycustDG.cs as the source file. /t imports all pertinent namespaces used in our control and /optimize optimizes our DLL for more efficiency.

Note: By default, .NET v1.1 may not have added the compiler's path to your environment variables. Therefore running this command line utility may not work as listed. To remedy this, add "%SystemRoot%\Microsoft.NET\Framework\v1.1.4322" to your System's Path Environment Variables, via Control Panel > System > Advanced > Environment Variables > System Variables > Path. Edit this variable, and append the aforementioned value to it. This way you could now execute any of the compilers anywhere without having to specify any full paths.

Now, once we've compiled our assembly, we import it at the top of our page using the @Register directive, like so, in conjunction to our custom Datagrid control tag above:

<%@ Register TagPrefix="DMGrid" Namespace="CustDataGrid" Assembly="myCustDG" %>

and when we setup our custom Datagrid we get the results that were shown in the image at the beginning of this article, and that's it!

As for VS.NET users, I have included the entire example as a VS.NET project in C# for download. All you need to do is create a new C# Web Application Project, compile the C# source file as a dll as mentioned, and reference it into to your project solution via Add New Reference.

To make it even easier for you, simply download the VS.NET Project code, as it contains everything I just mentioned. Now extract it into a folder named CustomDatagrid within wwwroot/inetpub, and simply double click the CustomDatagrid.sln file and voila.

The complete C# standard .NET page code:

<%@ Page language="C#" Inherits="CustDG.WebForm" Src="datagrid.aspx.cs" Debug="False" Explicit="True" Strict="True" Buffer="True" Trace="False" EnableSessionState="True" %>
<%@ Register TagPrefix="DMGrid" Namespace="CustDataGrid" Assembly="myCustDG" %>
<HTML>
<BODY onLoad="txtFocus();">
<BR>
<H2>Cached Custom Datagrid Control Class</H2>
    <form runat="server">
        <br>
        <asp:textbox id="srchTxt" runat="server" />
        <asp:button text="Search" id="Search" OnTextChanged="Rebind_Grid" AutoPostBack="True" runat="server" />
        <asp:button text="Reset" name="Reset" onClick="Reset_Grid" runat="server" />
        <BR><BR>
        <asp:label id="Stats" runat="server" />
        <BR><BR>
        <DMGrid:myCustDG ID="MyDataGrid" runat="server" autoCols="true" bgClr="Red" frClr="White" />
    </form>
</BODY>
</HTML>

And for all you VS.NET programmers, here is the VS C#.NET Project Solution - the .aspx page

<%@ Page language="C#" Inherits="CustDG.WebForm" Codebehind="datagrid.aspx.cs" Debug="False" Explicit="True" Strict="True" Buffer="True" Trace="False" EnableSessionState="True" %>
<%@ Register TagPrefix="DMGrid" Namespace="CustDataGrid" Assembly="myCustDG" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
    <HEAD>
        <title>Custom Datagrid Control</title>
        <%-- datagrid.aspx.cs contains our methods that interact with and control our Datagrid's functionality on this page --%>
        <meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
        <meta content="C#" name="CODE_LANGUAGE">
        <meta content="JavaScript" name="vs_defaultClientScript">
        <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
    </HEAD>
    <body onload="txtFocus();" MS_POSITIONING="GridLayout">
    <BR>
    <H2>Cached Custom Datagrid Control Class</H2>
    <form id="Form1" method="post" runat="server">
        <br>
        <asp:textbox id="srchTxt" runat="server" />
        <asp:button id="Search" onclick="Rebind_Grid" runat="server" text="Search" />
        <asp:button id="Reset" onclick="Reset_Grid" runat="server" text="Reset" />
        <BR><BR>
        <asp:label id="Stats" runat="server" />
        <BR><BR>
        <DMGrid:myCustDG ID="MyDataGrid" runat="server" autoCols="true" bgClr="Red" frClr="White" />
    </form>
    </body>
</HTML>

Below now I'll list the Code-Behind code applicable to both standard ASP.NET and Visual C#.NET applications. The only difference between the two is in the way each platform references the code-behind file. Both reference this file within their respective @Page Directives, however our standard C# page needs to reference this code with the "Src= file location" attribute, whereas VS.NET uses "Codebehind= file location" attribute.

//datagrid.aspx.cs Code-Behind Page
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
//Import mycustDG dll namespace so this code-behind page can access our custom Datagrid control on the main page.
using CustDataGrid;
namespace CustDG
{
    public class WebForm : System.Web.UI.Page //Inherit Page Class
    {
        protected System.Web.UI.WebControls.TextBox srchTxt;
        protected System.Web.UI.WebControls.Button Search;
        protected System.Web.UI.WebControls.Button Button1;
        protected System.Web.UI.WebControls.Label Stats;
        // Declare myDatagrid as myCustDG from referenced dll to allow code-behind Datagrid interaction with main Page Datagrid control properties
        public myCustDG MyDataGrid;

        public void Page_Load (Object Sender, EventArgs E)
        {

       //Implement Client Side JavaScript code
        StringBuilder jsScript = new StringBuilder();
        string nl = Environment.NewLine;        

        jsScript.Append ("<script language=JavaScript>" + nl);
        jsScript.Append ("<!--" + nl);
        jsScript.Append ("var isIE; " + nl);
        jsScript.Append ("if (navigator.appName == \"Microsoft Internet Explorer\"){isIE = true;} " + nl);
        jsScript.Append (" " + nl);
        jsScript.Append ("function getButton() " + nl);
        jsScript.Append ("{ " + nl);
        jsScript.Append (" //Capture Netscape events " + nl);
        jsScript.Append (" if(!isIE) { " + nl);
        jsScript.Append (" document.captureEvents(Event.KEYDOWN); " + nl);
        jsScript.Append (" } " + nl);
        jsScript.Append (" document.onkeydown = submitText" + nl);
        jsScript.Append ("} \n" + nl);
        jsScript.Append ("function submitText(evt){ \n" + nl);
        jsScript.Append (" var theButtonPressed; \n" + nl);
        jsScript.Append (" if (isIE){ " + nl);
        jsScript.Append (" theButtonPressed = window.event.keyCode; " + nl);
        jsScript.Append (" }else{ " + nl);
        jsScript.Append (" theButtonPressed = evt.which; " + nl);
        jsScript.Append (" } \n" + nl);
        jsScript.Append (" if (theButtonPressed == 13) { \n" + nl);
        jsScript.Append (" if(isIE){ " + nl);
        jsScript.Append (" with(event){ " + nl);
        jsScript.Append (" cancelBubble = true; " + nl);
        jsScript.Append (" returnValue = false; " + nl);
        jsScript.Append (" } " + nl);
        jsScript.Append (" } \n" + nl);
        jsScript.Append (" document.getElementById(\"Search\").click(); " + nl);
        jsScript.Append (" } " + nl);
        jsScript.Append ("} \n" + nl);
        jsScript.Append ("function txtFocus(){ \n" + nl);
        jsScript.Append (" with (document.getElementById(\"srchTxt\")){ " + nl);
        jsScript.Append (" focus(); " + nl);
        jsScript.Append (" select(); " + nl);
        jsScript.Append (" } \n" + nl);
        jsScript.Append ("} \n" + nl);
        jsScript.Append ("//--> " + nl);
        jsScript.Append ("</script>" + nl);

        //Allows our .NET page to add client-side script blocks when page loads, instead of the conventional HTML JS tags.
       RegisterClientScriptBlock("clientScript", jsScript.ToString());
       //Close our StringBuilder Object
        jsScript = null;

       srchTxt.Attributes.Add("onkeydown", "getButton();");
        Response.BufferOutput = true;       
            if (Page.IsPostBack)
            {
                //Set up our database connection string<
               MyDataGrid.strConn="server=(local);uid=sa;pwd=;database=Northwind;";
                MyDataGrid.Visible = true;
                MyDataGrid.autoCols = true;
                GridAction ();
            }
            //Response.Flush();
        }

        public void Rebind_Grid (Object Sender, EventArgs E)
        {
            HttpContext.Current.Session.Remove("dgCache"); //Remove session value to create new one before rebinding
            //HttpContext.Current.Cache.Remove("dgCache"); //Remove cache to create new one before rebinding
            Stats.Visible = true;
            MyDataGrid.CurrentPageIndex = 0;
            GridAction ();
        }

        public void GridAction ()
        {
            MyDataGrid.sqlQuery = "SELECT SupplierID As No, CompanyName, ContactName, Country FROM Suppliers where CompanyName like '%" + srchTxt.Text + "%' or ContactName like '%" + srchTxt.Text + "%' or Country like '%" + srchTxt.Text + "%' Order by CompanyName asc";
            MyDataGrid.GetDataGrid(); //Rebind Grid
        }

        public void Reset_Grid (Object Sender, EventArgs E)
        {
            HttpContext.Current.Session.RemoveAll(); //Remove session value to create new one before rebinding
            //HttpContext.Current.Cache.Remove("dgCache"); //Remove cache to create new one before rebinding
            srchTxt.Text = "";
            Stats.Visible = false;
            MyDataGrid.CurrentPageIndex = 0;
            MyDataGrid.Visible = false;
        }
    } // End Class
} //End Namespace

And the complete C# class source code for our compiled myCustDG dll used in our @Register Directive and referenced in our VS.NET project:

//C# - mycustDG.cs - Written by Dimitrios Markatos, 2003
using System.Reflection; //For assembly information attributes
[assembly: AssemblyTitle("Custom DataGrid Control")]
[assembly: AssemblyDescription("Pageable, Cacheable Datagrid Custom Control Class")]
[assembly: AssemblyCopyright("Dimitrios Markatos [[email protected]] - 2003")]
namespace CustDataGrid
{
    /// <summary>
    /// Custom Datagrid Control Class
    /// Author: Dimitrios Markatos - [email protected]
    /// Date: 5/22/2003
    /// </summary>
    using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.Diagnostics; //For Tracing
    using System.Drawing; // For Datagrid Colors
    using System.Web; // For HttpContext
    using System.Web.SessionState; // For HttpSessionState
    using System.Web.UI; //For Literal Controls
    using System.Web.UI.WebControls; // For Datagrid

    public class myCustDG : DataGrid
    { //Inherits the DataGrid Class
        // Internal private variables
        protected DataGrid MyDataGrid;
        protected DataSet objDS, dgCache;
        protected SqlConnection objConnect;
        protected SqlDataAdapter objDataAdapter;
        private bool _autoCols;
        private string _strConn, _sqlQuery;
        private Color _bgClr, _frClr;
        private int RcdCount, StartCnt, EndCnt; //_pageSz,
        int _bWidth = 0;
        //Allow external access to variables

        // DataGrid Set properties that get parameters from external control on page
        public string strConn
        {
            get { return _strConn; }
            set { _strConn = value; }
        }
        public bool autoCols
        {
            get { return _autoCols; }
            set { _autoCols = value; }
        }
        public string sqlQuery
        {
            get { return _sqlQuery; }
            set { _sqlQuery = value; }
        }

        public int bWidth
        {
            get { return _bWidth; }
            set { _bWidth = value; }
        }

        public Color bgClr
        {
            get { return _bgClr; }
            set { _bgClr = value; }
        }

        public Color frClr
        {
            get { return _frClr; }
            set { _frClr = value; }
        }

        protected override void OnPreRender(EventArgs e)
        {
            Control StatsCtrl = Page.FindControl("Stats");
            if (StatsCtrl != null)
            {
                if (Page.IsPostBack)
                {
                    if (RcdCount == 0)
                    {
                        StatsCtrl.Controls.Add(new LiteralControl("<font size=2><b>No Records Found</b></font>"));
                        Visible = false;
                    }
                    else
                    {
                        StatsCtrl.Controls.Add(new LiteralControl("<font size=2><b>Your search for <font color=red> " + HttpContext.Current.Request ["srchTxt"] + " </font>found " + RcdCount + " records / " + PageCount + " pages<BR>Results No. " + StartCnt + " to " + EndCnt + " / Page " + (CurrentPageIndex+1) + " of " + PageCount + "</b></font>"));
                        Visible = true;
                    }
                }
            }
        }

        public void GetDataGrid()
        {
            PageSize = 5;
            AutoGenerateColumns = autoCols;
            AllowPaging = true;
            GridLines = GridLines.None;
            BorderWidth = bWidth;
            BorderColor = Color.Black;
            ShowFooter = true;
            CellPadding = 3;
            CellSpacing = 0;
            Font.Name = "Verdana, Helvetica";
            Font.Bold = true;
            Font.Size = FontUnit.XXSmall;
            Width = 500;

            // Header Setting
            HeaderStyle.Font.Bold = true;
            HeaderStyle.BackColor = bgClr;
            HeaderStyle.ForeColor = frClr;
            HeaderStyle.HorizontalAlign = HorizontalAlign.Center;
            // Pagerstyle settings
            PagerStyle.Mode = PagerMode.NumericPages;
            PagerStyle.BackColor = Color.Gainsboro;
            PagerStyle.PageButtonCount = 10;
            PagerStyle.Font.Size = FontUnit.XSmall;
            PagerStyle.HorizontalAlign = HorizontalAlign.Right;
            DataSource = GridCachedData();

            try
            {
                DataBind();
            }
            catch
            {
                CurrentPageIndex = 0; //to catch any errors
            }
            PageIndexChanged += new DataGridPageChangedEventHandler (PageChanged);
            ItemCreated += new DataGridItemEventHandler (GridCreated);
            //Tracing inside a component
            // HttpContext.Current.Trace.Write ("Datagrid");
        }
        private DataSet GridCachedData()
        {
            //DataSet dgCache = (DataSet) HttpContext.Current.Cache.Get("dgCache");
            DataSet dgCache = (DataSet) HttpContext.Current.Session["dgCache"];
            if (dgCache == null)
            {
                SqlConnection objConnect = new SqlConnection(strConn);
                SqlDataAdapter objDataAdapter = new SqlDataAdapter (sqlQuery.ToString(), objConnect);
                DataSet objDS = new DataSet();
                //Create DataTable
                objDataAdapter.Fill (objDS);

                HttpContext.Current.Session.Add ("dgCache" ,objDS); // Session way
                //HttpContext.Current.Cache.Insert("dgCache", objDS, null,
                DateTime.Now.AddMinutes(10), TimeSpan.Zero); // Caching way
                RcdCount = objDS.Tables[0].Rows.Count;
                return objDS;
            }
            else
            {
                RcdCount = dgCache.Tables[0].Rows.Count;
                return dgCache;
            }
        }
        //Paging
        protected void PageChanged(Object sender, DataGridPageChangedEventArgs e)
        {
            CurrentPageIndex = e.NewPageIndex;
            GetDataGrid();
        }

        private void GridCreated(Object sender, DataGridItemEventArgs e)
        {

            //Declare the ItemType
            ListItemType elemType = e.Item.ItemType;

            if (elemType == ListItemType.Item || elemType == ListItemType.AlternatingItem)
            {
                //A DataGrid Item represents an item (row) in the DataGrid control
                //e.Item is the table row where the command is raised
                DataGridItem dgRow = (DataGridItem) e.Item;
                int rowCntIncr = dgRow.DataSetIndex + 1; //Gets the index number of the DataGridItem object from the bound data source
                //Get the start and end index count from datagrid
                //declare as typed variables first then convert
                StartCnt = rowCntIncr-dgRow.ItemIndex;
                EndCnt = rowCntIncr;
            }
        }

    } // End Class
} // End NameSpace

You might also like...

Comments

About the author

Dimitrios Markatos

Dimitrios Markatos United States

Dimitrios, or Jimmy as his friends call him, is a .NET developer/architect who specializes in Microsoft Technologies for creating high-performance and scalable data-driven enterprise Web and des...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“It is practically impossible to teach good programming style to students that have had prior exposure to BASIC. As potential programmers, they are mentally mutilated beyond hope of regeneration.” - E. W. Dijkstra