Friday, 7 March 2008

Creating Derived Controls

Introduction

In the previous lesson you developed a composite control by assembling existing server controls. There is one more technique to add to the functionality of the existing controls. You can extend existing controls and add/customize functionality as per your requirement. This way you avail the core functionality of the base control to create a tailor-made control meeting your requirement. The designer features of Visual Studio such as smart tags and dialogs that are available for the base control continue to remain available for the derived control also.

Example

As an example I am going to take up a common scenario. You might be aware that features of the GridView control such as paging and sorting work in code less fashion if you use data source controls (ODS or SDS). However, when you bind raw data in the form of say a DataSet to the GridView it forces you to write event handlers for Sorting and PageIndexChanging events. In most of the cases code within these event handlers look very similar. To reduce this repetition you can create your own grid control that inherits from GridView base class. You can then add the logic for sorting and paging inside this custom control.

To clearly understand how this can be done, create a new web site in Visual Studio. Add a class to it named MyGridView. The class definition should look as shown below:

namespace BinaryIntellect {   public class MyGridView:GridView   {   } }

Here, we created MyGridView class that inherits from GridView as its base class. This way all the functionality of GridView becomes available to our custom control class.

Then we need to create two helper methods viz. GetSortDirection() and BindGrid(). The GetSortDirection() method stores sort direction (ASC/DESC) in a ViewState variable. This is necessary because when you are not using any data source control for the purpose of data binding then GridView will not maintain the sorting direction by itself. The BindGrid() method bind the GridView with the required data. Internally it uses GetSortDirection() to sort the data on required column. These two functions are shown below:

private SortDirection GetSortDirection() { SortDirection dir; if (ViewState["_sortdirection"]==null) { ViewState["_sortdirection"] = "ASC"; dir = SortDirection.Ascending; } else { dir = (ViewState["_sortdirection"].ToString()  == "ASC" ? SortDirection.Ascending :  SortDirection.Descending); } ViewState["_sortdirection"] = (ViewState["_sortdirection"]. ToString() == "ASC" ? "DESC" : "ASC"); return dir; }  private void BindGrid(string sortExpression) { SqlDataAdapter da = new SqlDataAdapter("select * from  employees", @"data source=.\sqlexpress;initial  catalog=northwind;integrated security=true"); DataSet ds = new DataSet(); da.Fill(ds); DataView dv=ds.Tables[0].DefaultView; if (sortExpression != string.Empty) { ViewState["_sortexpression"] = sortExpression; dv.Sort = sortExpression + " " + (GetSortDirection()  == SortDirection.Ascending ? "ASC" : "DESC"); } else { if (ViewState["_sortexpression"] != null) { sortExpression = ViewState["_sortexpression"].ToString(); dv.Sort = sortExpression + " " + (GetSortDirection()  == SortDirection.Ascending ? "ASC" : "DESC"); } } this.DataSource = dv; this.DataBind(); }

The GetSortDirection() method returns the sort direction as SortDirection enumeration. The SortDirection enumeration is the same enumeration that GridView uses to represents its sorting direction. We persist the sort direction in a ViewState variable named _sortdirection. The possible values for this variable are ASC and DESC. Every time you cann GetSortDirection() method it returns existing direction to the caller and toggles the direction so that next time correct direction can be retirned. This is because if the grid is sorted in ascending order the first time then the next time we should sort it in descending order.

The BindGrid() method accepts the sort expression (Column name) on which you want to sort the data. It then proceeds to create a DataView containing the required data. In above code we are fetching all the records from Employees table of Northwind database. The DataView is then sorted using its Sort property and the return value of GetSortDirection() method. We also persist the sort expression in a ViewState variable so that sorting and paging can co-exist properly. The base GridView is then bound with the DataView.

Next, we override some events of the base class viz. Load, Sorting, Sorted, PageIndexChanging and PageIndexChanged. Their event handlers are shown below:

protected override void OnLoad(EventArgs e) { if (!this.Page.IsPostBack) { BindGrid(string.Empty); } }  protected override void OnSorting (GridViewSortEventArgs e) { BindGrid(e.SortExpression); } protected override void OnSorted(EventArgs e) { //nothing here } protected override void OnPageIndexChanging (GridViewPageEventArgs e) { this.PageIndex = e.NewPageIndex; BindGrid(string.Empty); } protected override void OnPageIndexChanged (EventArgs e) { //nothing here }

The OnLoad() method simply binds the grid during first load (IsPostBack is false). The OnSorting() method calls the BindGrid() method by passing the appropriate sort expression. The OnPageIndexChanging method sets the current page index of the grid using the NewPageIndex property and rebinds the grid. In our example we have not provided any specific code inside OnSorted() and OnPageIndexChanged() methods but you can add it if you so wish.

To use our MyGridView control on a web form, register it with the page using @Register directive.

<%@ Register Namespace="BinaryIntellect" TagPrefix="cc1"  %>

Also, create one instance of MyGridView in the form.

<cc1:MyGridView ID="GridView1" runat="server" AllowPaging="True"> </cc1:MyGridView>

Using Visual Studio designer add two BoundFields to the MyGridView control. Bind the first BoundField with FirstName column and the second with LastName column. Make sure to set their SortExpression property to FirstName and LastName respectively. Set AllowPaging and AllowSorting properties of MyGridView to true.

If you run the web form now you should something as shown below:

Try playing with sorting and paging functionality.
 
 

No comments: