Solved it myself by thinking about it in a different light: I now generate the links to the pages in RenderPreText, and I add a TreeNodeSelectAction.Select to each custom TreeNode -- I also set the ImageUrl of the TreeNode and when a user clicks on that, I can access the event and do what I need to do.
Mind you, I'm a bit baffled that it is so hard to do all this via the TreeView.
-----------------------------------------------------------------------------using System;
using System.Web.UI.WebControls;
namespace MySite
{
public class MyTreeView : TreeView
{
protected override TreeNode CreateNode()
{
return new MyTreeNode();
}
}
}
-----------------------------------------------------------------------------
using System;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MySite
{
public class MyTreeNode : TreeNode
{
private string NodeText = string.Empty;
private string NodeURL = string.Empty;
public MyTreeNode()
{
}
public MyTreeNode(string aText)
{
NodeText = aText;
}
public MyTreeNode(string aText, string aNavigateUrl,bool IsFavorite)
{
NodeText = aText;
NodeURL = aNavigateUrl;
if (NodeURL != null && NodeURL != string.Empty && NodeURL != "#")
{
if (IsFavorite)
{
this.ImageUrl = "~/Images/Remove.gif";
this.ImageToolTip = "remove from favorites";
}
else
{
this.ImageUrl = "~/Images/Add.gif";
this.ImageToolTip = "add to favorites";
}
}
this.Text = string.Empty;
this.Value = NodeURL;
this.SelectAction = TreeNodeSelectAction.Select;
}
protected override void RenderPreText(HtmlTextWriter writer)
{
bool bShowlink = false;
if (NodeURL != null && NodeURL != string.Empty && NodeURL != "#")
{
bShowlink = true;
}
// start span
writer.AddAttribute("class", "FavoriteURL");
writer.RenderBeginTag((HtmlTextWriterTag.Span));
if (bShowlink)
{
// start link
writer.AddAttribute("href", NodeURL);
writer.AddAttribute("title", "go to page");
writer.RenderBeginTag(HtmlTextWriterTag.A);
}
// write text
writer.Write(NodeText);
if (bShowlink)
{
// finish link
writer.RenderEndTag();
}
// finish span
writer.RenderEndTag();
base.RenderPreText(writer);
}
protected override object SaveViewState()
{
object[] arrState = new object[3];
arrState[0] = base.SaveViewState();
arrState[1] = this.NodeText;
arrState[2] = this.NodeURL;
return arrState;
}
protected override void LoadViewState(object savedState)
{
if (savedState != null)
{
object[] arrState = savedState as object[];
this.NodeText = (string)arrState[1];
this.NodeURL = (string)arrState[2];
base.LoadViewState(arrState[0]);
}
}
}
}
-----------------------------------------------------------------------------
the .aspx page (this is just the relevant code, not the complete page):
<%@ Register Assembly="MySite" Namespace="MySite" TagPrefix="My" %>
<My:MyTreeView ID="tvNavigation" runat="server" OnSelectedNodeChanged="Node_Selected" />
-----------------------------------------------------------------------------
namespace MySite
{
public partial class Explore : Page
{
private Hashtable htFavorites = new Hashtable();
protected void Page_Load(object sender, EventArgs e)
{
foreach (string sURL in Profile.Favorites)
{
htFavorites.Add(sURL, true);
}
if (!IsPostBack)
{
FillTree();
}
}
protected void Node_Selected(object sender, EventArgs e)
{
MyTreeView oSTV = (MyTreeView)sender;
string sSelectedURL = oSTV.SelectedNode.Value;
if (htFavorites[sSelectedURL] != null)
{
Profile.Favorites.Remove(sSelectedURL);
htFavorites.Remove(sSelectedURL);
}
else
{
Profile.Favorites.Add(sSelectedURL);
htFavorites.Add(sSelectedURL, true);
}
FillTree();
}
private void FillTree()
{
// needed because we rebuild the tree each time
tvNavigation.Nodes.Clear();
// ...code to add nodes to the tree...
tvNavigation.ExpandAll();
}
}
}
Life would be a lot easier if we could take a look at the source code.