Wednesday, September 01, 2004 11:47 AM
Christopher
Embrace and Extend: Creating a SiteMap from the squishyTREE server control.
I had been using the treeview from the IEWebControls library - which is great for IE, but just doesn't look or act so hot in anything else. So I wanted to find a TreeView control that would act as a SiteMap, and the squishyTREE control by squishyware fit the bill; almost perfectly. What the control lacked was a simple addition that would allow the use of hyperlinks without a postback.
Enter NavigateUrl.
The modifications I made were only in a few files:
- TreeNode.cs
- StandardRenderingAgent.cs
- TreeView.cs
I suppose this could go for the other RenderingAgents included with the control, but this is what I needed. You can see a live version here.
The code that supports the NavigateUrl property has to be in the TreeNode class, because that is what we will be clicking for navigation. The code:
public string NavigateUrl{ get{
object savedState = ViewState["NavigateUrl"];
if(savedState != null){
return savedState.ToString();
}
return string.Empty;
}
set{ ViewState["NavigateUrl"] = value; } }
Pretty simple so far. This code is just the standard server control property goop.
The container of the TreeNode, TreeView, had to be modified in a few places to allow using a url instead of simply a postback reference. Basically, I added support for anchor urls into the existing TreeView, modifying the overloaded methods where needed. Here are the places that were changed in TreeView.cs:
public void XmlBind(System.Xml.XmlDocument doc,
string urlAttribute,
string textAttribute,
string keyAttribute,
string checkAttribute,
string checkDefaultsAttribute){
foreach(XmlNode node in doc.DocumentElement.ChildNodes){
this.addChildNode(node,
urlAttribute,
textAttribute,
keyAttribute,
checkAttribute,
checkDefaultsAttribute);
}
}
public void XmlBind(System.Xml.XmlDocument doc,
string urlAttribute,
string textAttribute,
string keyAttribute){
this.XmlBind(doc, urlAttribute, textAttribute, keyAttribute, "", "");
}
private void addChildNode(XmlNode node,
string urlAttribute,
string textAttribute,
string keyAttribute,
string checkAttribute,
string checkDefaultsAttribute){
this.addChildNode(node,
urlAttribute,
textAttribute,
keyAttribute,
null,
checkAttribute,
checkDefaultsAttribute);
}
private void addChildNode(XmlNode node,
string urlAttribute,
string textAttribute,
string keyAttribute,
TreeNode tNode,
string checkAttribute,
string checkDefaultsAttribute){
string url = string.Empty;
string text;
string key = "";
bool checkbox = false;
bool isChecked = false;
if(node.Attributes[urlAttribute] != null){
url = node.Attributes[urlAttribute].Value;
}
text = node.Attributes[textAttribute].Value;
if(node.Attributes[keyAttribute] != null){
key = node.Attributes[keyAttribute].Value;
}
if(node.Attributes[checkAttribute] != null){
checkbox = Convert.ToBoolean(node.Attributes[checkAttribute].Value);
}
if(node.Attributes[checkDefaultsAttribute] != null){
isChecked = Convert.ToBoolean(node.Attributes[checkDefaultsAttribute].Value);
}
TreeNode n;
if(tNode == null){//add to the TreeView
n = this.AddNode(text, key, checkbox);
n.NavigateUrl = url;
}else{//add to the TreeNode
n = tNode.AddNode(text, key, checkbox);
n.NavigateUrl = url;
}
...
foreach(XmlNode child in node.ChildNodes){
if(child.Name != "taggedValue"){
this.addChildNode(child,
urlAttribute,
textAttribute,
keyAttribute,
n,
checkAttribute,
checkDefaultsAttribute);
}
}
protected override void LoadViewState(object savedState){
//load the treeview back from XML
if(savedState != null){
string xml = savedState.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
//xmlbind
this.XmlBind(doc,
TreeView.urlAttribute,
TreeView.textAttribute,
TreeView.keyAttribute,
TreeView.showChkAttribute,
TreeView.chkAttribute);
}
}
internal const string textAttribute = "t";
internal const string keyAttribute = "k";
internal const string chkAttribute = "c";
internal const string showChkAttribute = "s";
internal const string urlAttribute = "u"; //added this attribute
The code that was changed in StandardRenderingAgent was in the RenderNodeText(TreeNode node, HtmlTextWriter output) method:
if(!useLink) {
//name the anchor, in case you need to jump
output.Write("<a name='" + node.Key + "'> </a>");
output.WriteBeginTag("a");
if(node.NavigateUrl == string.Empty)
output.WriteAttribute("href",
this.TreeView.Page.GetPostBackClientHyperlink(this.TreeView, node.UniqueID),
false);
else
output.WriteAttribute("href", node.NavigateUrl, false);
output.WriteAttribute("class", this.TreeView.CssClass);
output.Write(HtmlTextWriter.TagRightChar); }
That's pretty much it. I think it was rather straightforward, plus the hard work was already done for me. Now I've got a simple SiteMap that will navigate to pages I specify at any time without postbacks.