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.