This post describes creation of an ASP.NET control for creating collapsible nodes within GridViews, incorporating JavaScript for expanding and collapsing child nodes, and implementing custom event handling for node selection.
Introduction
I recently started to create an ASP.NET control that had collapsible nodes. The GridView
s made a visual tree looking control based on the parent to child business object.
For example, a main node would expand to show a sub-main node and then the sub-main node would have element nodes.
All of these controls had GridView
s that contained JavaScript to expand or collapse the child nodes. There were several ways that I found on the net to hook into the postback of the controls.
The code contains the main Node that I used for creating a collapse image background with the name of the node and then another GridView
control called MainTreeNode
that I set the datasource
and bind to during the OnRowDataBound
event of the GridView
.
<table style="border:solid 1px gray; height:390px;">
<tr>
<td valign="top">
<asp:GridView ID="MainGridview" runat="server"
AutoGenerateColumns="false"
CellPadding="0"
CellSpacing="0"
GridLines="None"
ShowFooter="false"
ShowHeader="false"
OnRowDataBound="MainGridview_OnRowDataBound">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<table>
<tr>
<td>
<a href="javascript:ExpandCollapse('div<%# DataBinder.Eval(
Container.DataItem, "ID")%>', 'selector<%# DataBinder.Eval(
Container.DataItem, "ID")%>');">
<div id="selector<%# DataBinder.Eval(Container.DataItem, "ID")%>"
class="expandBar">
I am able to FindControl
to get the MainTreeNode
and then set the datasource
to the DataItem
’s property array.
The main question at this point is how to get an OnClick
event to fire from the MainTreeNode
. Note the OnNodeSelectedEvent="MainTreeNode_OnNodeSelected"
of the child.
This node event was achieved by creating a control event and having the IPostBackEventHandler
interface implemented on the node.
public partial class MainTreeNode: GrideView, IPostBackEventHandler
{
public bool AllowPostBack { get; set; }
protected override void OnRowDataBound(GridViewRowEventArgs e){
base.OnRowDataBound(e);
if(e.Row.DataItem != null && AllowPostBack){
string arg = string.Format("argument_{0}", e.Row.RowIndex);
e.Row.Attributes.Add("onclick",
Page.ClientScript.GetPostBackEventReference(this, arg));
}
}
protected override void PrepareControlHierarchy(){
base.PrepareControlHierarchy();
}
protected override void RaisePostBackEvent(string eventArgument){
base.RaisePostBackEvent(eventArgument);
}
}
Simplistic of course, but as noted above, there are several areas of the control that can be utilized. This would be the basic functionality of causing a postback on the clicking of the node (GridRow
).
The next item to make sure the control has handled is the custom event handler in the MainTreeNode
class:
protected override void RaisePostbackEvent(string argument){
if (argument != null){
NodeSelectedEventArg e = new NodeSelectedEventArg();
OnNodeSelected(e);
}
}
private static readonly object NodeSelectedEventKey = new object();
public event EventHandler<nodeselectedeventarg> NodeSelectedEvent{
add { Events.AddHandler(NodeSelectedEventKey, value); }
remove { Events.RemoveHandler(NodeSelectedEventKey, value); }
}
protected virtual void OnNodeSelected(NodeSelectedEventArg e){
base.RaiseEvent(NodeSelectedEventKey, e);
}
protected virtual void NodeSelected(object DataItem){
NodeSelectedEventArg e = new NodeSelectedEventArg();
e.dataItem = DataItem;
OnNodeSelected(e);
}
The event is now hooked into the control’s Events
collection and can be used if the containing control subscribes to the event. A delegate could also work here as well.
Now the code is provided as the building block foundation, more details will depend on the work that needs to be accomplished by the event. The event argument class can be created to handle any data item that needs to be persistent between controls, and I have found it very useful to keep the data item intact through custom event arguments.
My previous post had taken the original postback requirement into account, but as provided in the above code, moving the GetPostBackEventReference
method into OnRowDataBound
gives the option to have the GridView.Row.DataItem
available for keeping track of any data in the data item for the postback.
Hopefully, this will clear up any questions on the previous posting. I have worked with this control for a bit, and I am very pleased with how the GridView
reacted to the upgrade… :)
I have been coding since the 80's. Well that is kinda true, since I took Computer Science in College, however, it wasn't until Microsoft created an application called Office that I actually started coding in the real world.
Since 1995, I have been in the IT field and dabbled at creating Network Provider business to hook into the internet. At the time T1 lines were the bomb and very expensive, I had one. My partners created a workshop to introduce Windows 95, by selling computers with the operating system already installed. We would house classes of internet browsing and how to use Windows. My partners and I were initially involved in supporting the beta Windows 95 so we were well qualified to instruct on that subject.
I researched and developed all of the business web pages and web applications. My knowledge of VB helped me rise into the ranks of Contractor where I would then learn Java, HTML, and more.
I have since built thousands of web pages and applications, joined the .NET band wagon (though now I am having PHP fun). I currently support SOA Architecture for a marketing firm. I have had lots of fun with .NET. I have recently created websites for my company using MVC and Web API. I like to blog about my experiences when I have a major roadblock and my blogs usually wind up here.