I am in the process of creating a custom composite control.
Please comment on any mistakes or better ways you can think of doing things.
The Composite Control
The idea is to create a selector control. This involves some popping up a nice floating div in an appropriate place complete with appropriate textboxes and dropdowns for criteria selection and a pageable sortable list view underneath. The primary key or perhaps the row is clickable! this closes the box and selects the primary key. A cancel button is required also.
What's it Made of?
Inherit from CompositeControl
[ToolboxData("<{0}:Selector runat=server></{0}:Selector>")]
public class Selector : CompositeControlThe control is made up of a GridView, textboxes, comboboxes and some buttons. A LinkButton over the primary key perhaps.
Using the Control Execution Lifecycle I thought to put all the things that happen once when the control is initialised in OnInit.
Getting the data and putting it into the GridView. Also setting up some of the properties of the GridView.
Events
Right this is slightly hairy. I will describe what I have done but I think it is possible there are other solutions.
I noticed when I clicked a column to try and sort the grid that I got an unhandled event exception. Fair enough!
I went this way. Add a new EventHandler to the Sorting event on the GridView.
selectorGrid.Sorting += new GridViewSortEventHandler(selectorGrid_Sorting);
Visual Studio kindly allows you to press TAB to create the stubs and you end up with
void selectorGrid_Sorting(object sender, GridViewSortEventArgs e)
{
throw new Exception("The method or operation is not implemented.");
}
Now when the column is clicked you end up in the selectorGrid_Sorting method and the "The method or operation is not implemented." exception is thrown.
The sort now has to be handled by the composite. Of course, you cannot use the Sort method on the GridView because you will end up in the Sorting Event and get an Overflow exception.
As the control is loaded every time any state must be preserved manually using the ViewState["myThingIWantToSave"] array.
private GridViewSortEventArgs SortArgs
{
get
{
if (ViewState["SortExpression"] != null && ViewState["SortDirection"] != null)
{
_sortValues.SortExpression = (String)ViewState["SortExpression"];
_sortValues.SortDirection = (SortDirection)ViewState["SortDirection"];
}
return _sortValues;
}
set
{
_sortValues = value;
ViewState["SortExpression"] = _sortValues.SortExpression;
ViewState["SortDirection"] = _sortValues.SortDirection;
}
}
_sortValues is private variable. It means I can have property of the right type and put defaults in. SortDirection is not Serializable either.
My event ends up looking like this:
void selectorGrid_Sorting(object sender, GridViewSortEventArgs e)
{
EnsureChildControls();
//reset to Ascending if changing expression
if (SortArgs.SortExpression != e.SortExpression)
SortArgs.SortDirection = SortDirection.Ascending;
else
//if the expression is the same just toggle the direction
_sortValues.SortDirection = SortArgs.SortDirection == SortDirection.Ascending ? SortDirection.Descending : SortDirection.Ascending;
_sortValues.SortExpression = e.SortExpression;
//Save to ViewState
SortArgs = _sortValues;
//Sort the data in the Grid
SortGrid();
} Here is SortGrid
private void SortGrid()
{
DataTable dt = ds.Tables[0];
DataView dv = new DataView(dt);
if (SortArgs.SortExpression.Length > 0 )
dv.Sort = SortArgs.SortExpression + " " + (SortArgs.SortDirection == SortDirection.Ascending ? "ASC": "DESC");
selectorGrid.DataSource = dv;
selectorGrid.DataBind();
}
Page Indexing works in a similar way except you don't have to worry about ViewState because the GridView does it internally.
Blogged with Flock
No comments:
Post a Comment