Creating custom TreeView/TreeNode
asp.net, c#, treenode, treeview, webforms
Solution
This is what I came up with (experts, any advice welcomed). Instantiate the `CustomTreeNode`s in your code behind and set the properties via setters. Modify your `CustomTreeNode` class to persist the values in ViewState. The node returned by your custom tree view's `CreateNode` will load the ViewState information.
TreeNode class:
[DefaultProperty("Text")]
[ToolboxData("<{0}:CustomTreeNode runat=server></{0}:CustomTreeNode>")]
public class CustomTreeNode : TreeNode
{
private const int NODE_TYPE = 1;
private const int NODE_ID = 2;
public string NodeType { get; set; }
public int NodeId { get; set; }
protected override void LoadViewState(Object savedState)
{
if (savedState != null)
{
object[] myState = (object[])savedState;
if (myState[0] != null)
base.LoadViewState(myState[0]);
if (myState[NODE_TYPE] != null)
this.NodeType = (string)myState[NODE_TYPE];
if (myState[NODE_ID] != null)
this.NodeId = (int)myState[NODE_ID];
}
}
protected override Object SaveViewState()
{
object baseState = base.SaveViewState();
object[] allStates = new object[3];
allStates[0] = baseState;
allStates[NODE_TYPE] = this.NodeType;
allStates[NODE_ID] = this.NodeId;
return allStates;
}
}
TreeView class:
[DefaultProperty("Text")]
[ToolboxData("<{0}:CustomTreeView runat=server></{0}:CustomTreeView>")]
public class CustomTreeView : TreeView
{
protected override TreeNode CreateNode()
{
// Tree node will get its members populated with the data from VIEWSTATE
return new CustomTreeNode();
}
}
Simple .aspx file (Assuming that your custom control is defined in an assembly "Foo" and a namespace "Bar":
<%@ Register TagPrefix="customControl" Assembly="Foo" Namespace="Bar" %>
<customControl:CustomTreeView ID="sampleTree"
runat="server" onselectednodechanged="sampleTree_SelectedNodeChanged"></customControl:CustomTreeView>
<asp:Label ID="lblSelectedNode" runat="server" ></asp:Label>
CodeBehind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
PopulateTree();
}
}
private void PopulateTree()
{
sampleTree.Nodes.Clear();
CustomTreeNode root = new CustomTreeNode();
root.Value = "root node";
sampleTree.Nodes.Add(root);
// Creating some fake nodes (you would of course be using real data)
for (int i = 0; i < 10; i++)
{
CustomTreeNode child = new CustomTreeNode();
child.NodeId = i; // Saved in ViewState
child.NodeType = "Type " + i; // Saved in ViewState
child.Value = child.NodeType;
root.ChildNodes.Add(child);
}
}
protected void sampleTree_SelectedNodeChanged(object sender, EventArgs e)
{
CustomTreeView cTreeView = (CustomTreeView) sender;
lblSelectedNode.Text = ((CustomTreeNode)cTreeView.SelectedNode).NodeType;
}
Problem
I need to extend the TreeNode class such that I can add custom properties to each node (seeing as WebForms TreeNode doesn't include the Tag property). So this is my CustomTreeNode: ``` public class CustomTreeNode : TreeNode { public CustomTreeNode() { } public CustomTreeNode(int nodeId, string nodeType) { NodeId = nodeId; NodeType = nodeType; } public string NodeType { get; set; } public int NodeId { get; set; } } ``` If I create a CustomTreeNode and add it to a TreeView: ``` CustomTreeNode node = new CustomTreeNode(1, "CustomType"); treeView.Nodes.Add(node); ``` I would then get a casting exception doing the following: ``` CustomTreeNode selectedNode = (CustomTreeNode)TreeView.SelectedNode; ``` because TreeView returns a TreeNode, not a CustomTreeNode. I've done some reading, and it looks like I need to extend the TreeView class, and override the CreateNode() method to return CustomTreeNode instead of TreeNode. So I created this: ``` public class CustomTreeView : TreeView { protected override TreeNode CreateNode() { return new CustomTreeNode(); } } ``` The problem is however, CreateNode() doesn't take any arguments, so you have to have call the empty constructor for the CustomTreeNode class. So when I created my CustomTreeNode above, when I get it back from the CustomTreeView, the nodeId and nodeType values have been lost because the empty constructor returns a node without any values. Any help much appreciated.