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.

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)