Building a Full-Featured Custom DataGrid Control

Let's Cache

Now onto the piece d' resistance, our data caching. Within our datagrid class, we include our method GetDataGrid() which set's up all we've discussed - our grid's properties, event handlers, etc. Now as I mentioned before, I nevertheless, in this example, assigned my Datagrid's datasource to another method.

As shown, within our method below we create our connections, get our Dataset and return our results so our DataSource may be bound.

using System.Web.SessionState;  // For HttpSessionState
// Our main constructor
public void GetDataGrid() {
    ...
    DataSource = GridDataCache(); //Gets bound from DataSet method below
    ...
}

Now the GridDataCache method once called will return the data to which our DataSource gets assigned, and as we'll now explore can be either standard data or cached data.

private DataSet GridCachedData()
{
    // Data Caching - Session API
    DataSet dgCache = (DataSet) HttpContext.Current.Session ["dgCache"];
    // Data Caching - Web Cache API
    //DataSet dgCache = (DataSet) HttpContext.Current.Cache.Get ("dgCache");
    //Check first to see if our cache already exists
    if (dgCache == null)
    {
        // Get data from database and create Dataset
        // ...
        // Insert Dataset into Session Object
        HttpContext.Current.Session.Add ("dgCache" ,objDS);
        // Alternatively, insert Dataset into Data Cache
        //HttpContext.Current.Cache.Insert ("dgCache", objDS, null, DateTime.Now.AddMinutes(10), TimeSpan.Zero);
        return objDS;
    }
    else
    {
        //Since cache now exists, return cached Dataset
        return dgCache;
    }
}

OK, let's examine what's taking place here. Aside from commonplace database opening and connecting, we utilize data caching that we've set up accordingly. These techniques are straightforward and I would advise you reading both Drilldown Datagrid Searching with ASP.NET and .NET Data Caching for an exact methodology to what we're doing here. However, since we are implementing caching within our component, the common caching methods when working with the web cache API discussed in my articles won't work in this case. Why? When implementing caching inside of a component, by its very nature, you'll need the find the cache object through the current HTTP request via the HttpContext.Cache Class property. The common System.Web.Caching object cannot accommodate us in this fashion.

Notice how I list two ways of doing the same thing, one is utilizing the Session API and the other the Cache API. Both have their advantages and disadvantages, that were amply discussed in my Drilldown Datagrid article above. Therefore, after reading my prior articles, you'll find the techniques to be the same, save using HttpContext instead of what I demonstrated there, and the case for either caching method.

Moreover, also notice that with each newly created search, we always need to clear any prior cached data. Therefore, within our .NET page you'll notice that our server-side methods do this for us.

HttpContext.Current.Session.Remove ("dgCache");

In this instance, we remove any prior values kept in session state.

Note: Later on, you can test this new caching/paging implementation by commenting out the return dgCache, recompile it and then start paging. Hmm, no page 2. That's because there is no data. Another test is in our page I added a reset button that will remove this cache from memory and reset our Datagrid. Commenting this out, and re-searching will bring you back the previously cached results!

Well, keep this in mind as we'll get to compiling our class and importing it into our page. Before this, we'll touch on the last of our classes methods. This is a nice one, which is responsible for writing to our label control all our statistics, as we briefly noted at the beginning.

Displaying Our Results

Again, on our page we have all our pertinent web server controls, but only one of those is responsible for displaying our data statistics that emanate from within our DLL. So how does this all happen? We accomplish this in our component with a wonderful little method called OnPreRender, that sends to our Stats Label server control (that we use more or less as a placeholder, which it literally can be as well) - "Your search for X found X records / Results No. 16 to 20, Page 4 of 6, etc." But prior to sending our statistics to our page's server control, we 1) check to see it even exists (otherwise no stats will display) and 2) display our results only upon Page.IsPostback. Anyway here it is:

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>"));
        }
    }
}

Now what's this again? Well, this method overrides the Control.OnPreRender method that typically occurs when the server control is about to render to the page, and before any viewstate content is saved. We use this opportunity within our Datagrid class to gather all our stats in one swell foop, and send them to our Stats server control on our main page. How is this done? We declare our Stats control as a Control (StatsCtrl) to which we use the FindControl method to locate it on our page, and add the new LiteralControl object to the located server control's Control.Controls property.

The e EventArgs parameter contains the event data handled by our method. Even still, when the overriding occurs, it writes out the datagrid paging statistics drawn from within the very class this method resides, to our Stats label server control before rendering any content to the user and before view state is enabled, consequentially paralleling our datagrid paging events. Additionally since we need to also know what criteria the user entered, we can obtain this information using HttpContext.Current.Request ["srchTxt"] which is the HttpRequest object for our current HTTP request.

Try this quick test to see the order you render your controls. Add trace="true" to your @Page Directive and in our OnPreRender method add - HttpContext.Current.Trace.Write ("Here I Am") and then recompile; and you'll see that this indeed overrides OnPreRender.

I hope I haven't lost you so far. Moving on, since we pull into our page values from our compiled class as demonstrated earlier, assigning values to your custom Datagrid control works in the same exact way. So to set the pageSz, for instance, to 10, on Page_Load perhaps, you can write - MyDataGrid.pageSz = 10; - and voila, the datagrid will display 10 records per page.

Incidentally, within your page, you would access the datagrid using its ID. However, since your compiled class is a Datagrid control itself, any values assigned internally, all that is needed is the the datagrid property alone.

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.

“Brevity is the soul of wit” - Shakespeare