2 // System.Web.UI.WebControls.TreeView.cs
5 // Lluis Sanchez Gual (lluis@novell.com)
7 // (C) 2004 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
33 using System.Collections;
35 using System.ComponentModel;
36 using System.Globalization;
37 using System.Web.Handlers;
38 using System.Collections.Specialized;
40 using System.Security.Permissions;
41 using System.Collections.Generic;
42 using System.Web.Util;
44 namespace System.Web.UI.WebControls
47 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
50 [SupportsEventValidation]
51 [ControlValueProperty ("SelectedValue")]
52 [DefaultEvent ("SelectedNodeChanged")]
53 [Designer ("System.Web.UI.Design.WebControls.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
54 public class TreeView: HierarchicalDataBoundControl, IPostBackEventHandler, IPostBackDataHandler, ICallbackEventHandler
56 string activeSiteMapPath;
59 TreeNodeStyle leafNodeStyle;
60 TreeNodeStyle nodeStyle;
61 TreeNodeStyle parentNodeStyle;
62 TreeNodeStyle rootNodeStyle;
63 TreeNodeStyle selectedNodeStyle;
65 TreeNodeStyleCollection levelStyles;
66 TreeNodeCollection nodes;
67 TreeNodeBindingCollection dataBindings;
69 TreeNode selectedNode;
72 int registeredStylesCounter = -1;
73 List<Style> levelLinkStyles;
74 Style controlLinkStyle;
76 Style rootNodeLinkStyle;
77 Style parentNodeLinkStyle;
78 Style leafNodeLinkStyle;
79 Style selectedNodeLinkStyle;
80 Style hoverNodeLinkStyle;
82 static readonly object TreeNodeCheckChangedEvent = new object();
83 static readonly object SelectedNodeChangedEvent = new object();
84 static readonly object TreeNodeCollapsedEvent = new object();
85 static readonly object TreeNodeDataBoundEvent = new object();
86 static readonly object TreeNodeExpandedEvent = new object();
87 static readonly object TreeNodePopulateEvent = new object();
89 static Hashtable imageStyles = new Hashtable ();
91 class TreeViewExpandDepthConverter : TypeConverter
93 public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
95 if (sourceType == typeof (string) || sourceType == typeof (int))
98 return base.CanConvertFrom (context, sourceType);
101 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
103 if (destinationType == typeof (string) || destinationType == typeof (int))
106 return base.CanConvertTo (context, destinationType);
109 public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
111 if (destinationType != typeof (int) && destinationType != typeof (string))
112 return base.ConvertTo (context, culture, value, destinationType);
114 if (value is string) {
115 if (destinationType == typeof (int)) {
116 if (String.Compare ("FullyExpand", (string)value, StringComparison.OrdinalIgnoreCase) == 0)
120 return Int32.Parse ((string)value);
121 } catch (Exception) {
128 int val = (int)value;
129 if (destinationType == typeof (string)) {
131 return "FullyExpand";
132 return val.ToString ();
138 public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value)
140 if (!(value is string) && !(value is int))
141 return base.ConvertFrom (context, culture, value);
143 if (value is string) {
144 if (String.Compare ("FullyExpand", (string)value, StringComparison.OrdinalIgnoreCase) == 0)
148 return Int32.Parse ((string)value);
149 } catch (Exception) {
160 public ImageStyle (string expand, string collapse, string noExpand, string icon, string iconLeaf, string iconRoot)
170 public string Expand;
171 public string Collapse;
172 public string NoExpand;
173 public string RootIcon;
174 public string ParentIcon;
175 public string LeafIcon;
180 imageStyles [TreeViewImageSet.Arrows] = new ImageStyle ("arrow_plus", "arrow_minus", "arrow_noexpand", null, null, null);
181 imageStyles [TreeViewImageSet.BulletedList] = new ImageStyle (null, null, null, "dot_full", "dot_empty", "dot_full");
182 imageStyles [TreeViewImageSet.BulletedList2] = new ImageStyle (null, null, null, "box_full", "box_empty", "box_full");
183 imageStyles [TreeViewImageSet.BulletedList3] = new ImageStyle (null, null, null, "star_full", "star_empty", "star_full");
184 imageStyles [TreeViewImageSet.BulletedList4] = new ImageStyle (null, null, null, "star_full", "star_empty", "dots");
185 imageStyles [TreeViewImageSet.Contacts] = new ImageStyle ("TreeView_plus", "TreeView_minus", "contact", null, null, null);
186 imageStyles [TreeViewImageSet.Events] = new ImageStyle (null, null, null, "warning", "warning", "warning");
187 imageStyles [TreeViewImageSet.Inbox] = new ImageStyle (null, null, null, "inbox", "inbox", "inbox");
188 imageStyles [TreeViewImageSet.Msdn] = new ImageStyle ("box_plus", "box_minus", "box_noexpand", null, null, null);
189 imageStyles [TreeViewImageSet.Simple] = new ImageStyle (null, null, "box_full", null, null, null);
190 imageStyles [TreeViewImageSet.Simple2] = new ImageStyle (null, null, "box_empty", null, null, null);
193 imageStyles [TreeViewImageSet.News] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
194 imageStyles [TreeViewImageSet.Faq] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
195 imageStyles [TreeViewImageSet.WindowsHelp] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
196 imageStyles [TreeViewImageSet.XPFileExplorer] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", "folder", "file", "computer");
199 public event TreeNodeEventHandler TreeNodeCheckChanged {
200 add { Events.AddHandler (TreeNodeCheckChangedEvent, value); }
201 remove { Events.RemoveHandler (TreeNodeCheckChangedEvent, value); }
204 public event EventHandler SelectedNodeChanged {
205 add { Events.AddHandler (SelectedNodeChangedEvent, value); }
206 remove { Events.RemoveHandler (SelectedNodeChangedEvent, value); }
209 public event TreeNodeEventHandler TreeNodeCollapsed {
210 add { Events.AddHandler (TreeNodeCollapsedEvent, value); }
211 remove { Events.RemoveHandler (TreeNodeCollapsedEvent, value); }
214 public event TreeNodeEventHandler TreeNodeDataBound {
215 add { Events.AddHandler (TreeNodeDataBoundEvent, value); }
216 remove { Events.RemoveHandler (TreeNodeDataBoundEvent, value); }
219 public event TreeNodeEventHandler TreeNodeExpanded {
220 add { Events.AddHandler (TreeNodeExpandedEvent, value); }
221 remove { Events.RemoveHandler (TreeNodeExpandedEvent, value); }
224 public event TreeNodeEventHandler TreeNodePopulate {
225 add { Events.AddHandler (TreeNodePopulateEvent, value); }
226 remove { Events.RemoveHandler (TreeNodePopulateEvent, value); }
229 protected virtual void OnTreeNodeCheckChanged (TreeNodeEventArgs e)
231 if (Events != null) {
232 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCheckChangedEvent];
238 protected virtual void OnSelectedNodeChanged (EventArgs e)
240 if (Events != null) {
241 EventHandler eh = (EventHandler) Events [SelectedNodeChangedEvent];
247 protected virtual void OnTreeNodeCollapsed (TreeNodeEventArgs e)
249 if (Events != null) {
250 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCollapsedEvent];
256 protected virtual void OnTreeNodeDataBound (TreeNodeEventArgs e)
258 if (Events != null) {
259 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeDataBoundEvent];
265 protected virtual void OnTreeNodeExpanded (TreeNodeEventArgs e)
267 if (Events != null) {
268 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeExpandedEvent];
274 protected virtual void OnTreeNodePopulate (TreeNodeEventArgs e)
276 if (Events != null) {
277 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodePopulateEvent];
285 public string CollapseImageToolTip {
286 get { return ViewState.GetString ("CollapseImageToolTip", "Collapse {0}"); }
287 set { ViewState["CollapseImageToolTip"] = value; }
290 [MonoTODO ("Implement support for this")]
291 [WebCategory ("Behavior")]
292 [WebSysDescription ("Whether the tree will automatically generate bindings.")]
293 [DefaultValue (true)]
294 public bool AutoGenerateDataBindings {
295 get { return ViewState.GetBool ("AutoGenerateDataBindings", true); }
296 set { ViewState["AutoGenerateDataBindings"] = value; }
300 [WebSysDescription ("The url of the image to show when a node can be collapsed.")]
302 [WebCategory ("Appearance")]
303 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
304 public string CollapseImageUrl {
305 get { return ViewState.GetString ("CollapseImageUrl", String.Empty); }
306 set { ViewState["CollapseImageUrl"] = value; }
309 [WebCategory ("Data")]
310 [PersistenceMode (PersistenceMode.InnerProperty)]
311 [WebSysDescription ("Bindings for tree nodes.")]
312 [Editor ("System.Web.UI.Design.WebControls.TreeViewBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
313 [DefaultValue (null)]
314 [MergablePropertyAttribute (false)]
315 public TreeNodeBindingCollection DataBindings {
317 if (dataBindings == null) {
318 dataBindings = new TreeNodeBindingCollection ();
319 if (IsTrackingViewState)
320 ((IStateManager)dataBindings).TrackViewState();
326 [WebCategory ("Behavior")]
327 [WebSysDescription ("Whether the tree view can use client-side script to expand and collapse nodes.")]
329 [DefaultValue (true)]
330 public bool EnableClientScript {
331 get { return ViewState.GetBool ("EnableClientScript", true); }
332 set { ViewState["EnableClientScript"] = value; }
336 [WebCategory ("Behavior")]
337 [WebSysDescription ("The initial expand depth.")]
338 [TypeConverter ("System.Web.UI.WebControls.TreeView+TreeViewExpandDepthConverter, " + Consts.AssemblySystem_Web)]
339 public int ExpandDepth {
340 get { return ViewState.GetInt ("ExpandDepth", -1); }
341 set { ViewState["ExpandDepth"] = value; }
345 public string ExpandImageToolTip {
346 get { return ViewState.GetString ("ExpandImageToolTip", "Expand {0}"); }
347 set { ViewState["ExpandImageToolTip"] = value; }
352 [WebSysDescription ("The url of the image to show when a node can be expanded.")]
353 [WebCategory ("Appearance")]
354 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
355 public string ExpandImageUrl {
356 get { return ViewState.GetString ("ExpandImageUrl", String.Empty); }
357 set { ViewState["ExpandImageUrl"] = value; }
360 [PersistenceMode (PersistenceMode.InnerProperty)]
361 [NotifyParentProperty (true)]
362 [DefaultValue (null)]
363 [WebCategory ("Styles")]
364 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
365 public Style HoverNodeStyle {
367 if (hoverNodeStyle == null) {
368 hoverNodeStyle = new Style();
369 if (IsTrackingViewState)
370 hoverNodeStyle.TrackViewState();
372 return hoverNodeStyle;
376 [DefaultValue (TreeViewImageSet.Custom)]
377 public TreeViewImageSet ImageSet {
378 get { return (TreeViewImageSet)ViewState.GetInt ("ImageSet", (int)TreeViewImageSet.Custom); }
380 if (!Enum.IsDefined (typeof (TreeViewImageSet), value))
381 throw new ArgumentOutOfRangeException ();
382 ViewState["ImageSet"] = value;
386 [PersistenceMode (PersistenceMode.InnerProperty)]
387 [NotifyParentProperty (true)]
388 [DefaultValue (null)]
389 [WebCategory ("Styles")]
390 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
391 public TreeNodeStyle LeafNodeStyle {
393 if (leafNodeStyle == null) {
394 leafNodeStyle = new TreeNodeStyle ();
395 if (IsTrackingViewState)
396 leafNodeStyle.TrackViewState();
398 return leafNodeStyle;
402 [DefaultValue (null)]
403 [WebCategory ("Styles")]
404 [PersistenceMode (PersistenceMode.InnerProperty)]
405 [Editor ("System.Web.UI.Design.WebControls.TreeNodeStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
406 public TreeNodeStyleCollection LevelStyles {
408 if (levelStyles == null) {
409 levelStyles = new TreeNodeStyleCollection ();
410 if (IsTrackingViewState)
411 ((IStateManager)levelStyles).TrackViewState();
418 public string LineImagesFolder {
419 get { return ViewState.GetString ("LineImagesFolder", String.Empty); }
420 set { ViewState["LineImagesFolder"] = value; }
424 public int MaxDataBindDepth {
425 get { return ViewState.GetInt ("MaxDataBindDepth", -1); }
426 set { ViewState["MaxDataBindDepth"] = value; }
430 public int NodeIndent {
431 get { return ViewState.GetInt ("NodeIndent", 20); }
432 set { ViewState["NodeIndent"] = value; }
435 [PersistenceMode (PersistenceMode.InnerProperty)]
436 [Editor ("System.Web.UI.Design.WebControls.TreeNodeCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
437 [DefaultValueAttribute (null)]
438 [MergablePropertyAttribute (false)]
439 public TreeNodeCollection Nodes {
442 nodes = new TreeNodeCollection (this);
443 if (IsTrackingViewState)
444 ((IStateManager)nodes).TrackViewState();
450 [PersistenceMode (PersistenceMode.InnerProperty)]
451 [NotifyParentProperty (true)]
452 [DefaultValue (null)]
453 [WebCategory ("Styles")]
454 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
455 public TreeNodeStyle NodeStyle {
457 if (nodeStyle == null) {
458 nodeStyle = new TreeNodeStyle ();
459 if (IsTrackingViewState)
460 nodeStyle.TrackViewState();
466 [DefaultValue (false)]
467 public bool NodeWrap {
468 get { return ViewState.GetBool ("NodeWrap", false); }
469 set { ViewState ["NodeWrap"] = value; }
474 [WebSysDescription ("The url of the image to show for leaf nodes.")]
475 [WebCategory ("Appearance")]
476 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
477 public string NoExpandImageUrl {
478 get { return ViewState.GetString ("NoExpandImageUrl", String.Empty); }
479 set { ViewState ["NoExpandImageUrl"] = value; }
482 [PersistenceMode (PersistenceMode.InnerProperty)]
483 [NotifyParentProperty (true)]
484 [DefaultValue (null)]
485 [WebCategory ("Styles")]
486 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
487 public TreeNodeStyle ParentNodeStyle {
489 if (parentNodeStyle == null) {
490 parentNodeStyle = new TreeNodeStyle ();
491 if (IsTrackingViewState)
492 parentNodeStyle.TrackViewState();
494 return parentNodeStyle;
499 public char PathSeparator {
500 get { return ViewState.GetChar ("PathSeparator", '/'); }
501 set { ViewState ["PathSeparator"] = value; }
504 [DefaultValue (true)]
505 public bool PopulateNodesFromClient {
506 get { return ViewState.GetBool ("PopulateNodesFromClient", true); }
507 set { ViewState ["PopulateNodesFromClient"] = value; }
510 [PersistenceMode (PersistenceMode.InnerProperty)]
511 [NotifyParentProperty (true)]
512 [DefaultValue (null)]
513 [WebCategory ("Styles")]
514 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
515 public TreeNodeStyle RootNodeStyle {
517 if (rootNodeStyle == null) {
518 rootNodeStyle = new TreeNodeStyle ();
519 if (IsTrackingViewState)
520 rootNodeStyle.TrackViewState();
522 return rootNodeStyle;
526 [PersistenceMode (PersistenceMode.InnerProperty)]
527 [NotifyParentProperty (true)]
528 [DefaultValue (null)]
529 [WebCategory ("Styles")]
530 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
531 public TreeNodeStyle SelectedNodeStyle {
533 if (selectedNodeStyle == null) {
534 selectedNodeStyle = new TreeNodeStyle ();
535 if (IsTrackingViewState)
536 selectedNodeStyle.TrackViewState();
538 return selectedNodeStyle;
542 Style ControlLinkStyle {
544 if (controlLinkStyle == null) {
545 controlLinkStyle = new Style ();
546 controlLinkStyle.AlwaysRenderTextDecoration = true;
548 return controlLinkStyle;
552 Style NodeLinkStyle {
554 if (nodeLinkStyle == null) {
555 nodeLinkStyle = new Style ();
557 return nodeLinkStyle;
561 Style RootNodeLinkStyle {
563 if (rootNodeLinkStyle == null)
564 rootNodeLinkStyle = new Style ();
565 return rootNodeLinkStyle;
569 Style ParentNodeLinkStyle {
571 if (parentNodeLinkStyle == null)
572 parentNodeLinkStyle = new Style ();
573 return parentNodeLinkStyle;
577 Style SelectedNodeLinkStyle {
579 if (selectedNodeLinkStyle == null)
580 selectedNodeLinkStyle = new Style ();
581 return selectedNodeLinkStyle;
585 Style LeafNodeLinkStyle {
587 if (leafNodeLinkStyle == null)
588 leafNodeLinkStyle = new Style ();
589 return leafNodeLinkStyle;
593 Style HoverNodeLinkStyle {
595 if (hoverNodeLinkStyle == null)
596 hoverNodeLinkStyle = new Style ();
597 return hoverNodeLinkStyle;
601 [DefaultValue (TreeNodeTypes.None)]
602 public TreeNodeTypes ShowCheckBoxes {
603 get { return (TreeNodeTypes)ViewState.GetInt ("ShowCheckBoxes", (int)TreeNodeTypes.None); }
606 throw new ArgumentOutOfRangeException ();
607 ViewState ["ShowCheckBoxes"] = value;
611 [DefaultValue (true)]
612 public bool ShowExpandCollapse {
613 get { return ViewState.GetBool ("ShowExpandCollapse", true); }
614 set { ViewState ["ShowExpandCollapse"] = value; }
617 [DefaultValue (false)]
618 public bool ShowLines {
619 get { return ViewState.GetBool ("ShowLines", false); }
620 set { ViewState ["ShowLines"] = value; }
624 public string SkipLinkText
626 get { return ViewState.GetString ("SkipLinkText", "Skip Navigation Links."); }
627 set { ViewState ["SkipLinkText"] = value; }
632 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
633 public TreeNode SelectedNode {
634 get { return selectedNode; }
639 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
640 public string SelectedValue {
641 get { return selectedNode != null ? selectedNode.Value : String.Empty; }
645 public string Target {
646 get { return ViewState.GetString ("Target", String.Empty); }
647 set { ViewState ["Target"] = value; }
650 [MonoTODO ("why override?")]
651 public override bool Visible
653 get { return base.Visible; }
654 set { base.Visible = value; }
658 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
659 public TreeNodeCollection CheckedNodes {
661 TreeNodeCollection col = new TreeNodeCollection ();
662 FindCheckedNodes (Nodes, col);
667 void FindCheckedNodes (TreeNodeCollection nodeList, TreeNodeCollection result)
669 foreach (TreeNode node in nodeList) {
671 result.Add (node, false);
672 FindCheckedNodes (node.ChildNodes, result);
676 public void ExpandAll ()
678 foreach (TreeNode node in Nodes)
682 public void CollapseAll ()
684 foreach (TreeNode node in Nodes)
688 public TreeNode FindNode (string valuePath)
690 if (valuePath == null)
691 throw new ArgumentNullException ("valuePath");
692 string[] path = valuePath.Split (PathSeparator);
694 TreeNodeCollection col = Nodes;
695 bool foundBranch = true;
696 while (col.Count > 0 && foundBranch) {
698 foreach (TreeNode node in col) {
699 if (node.Value == path [n]) {
700 if (++n == path.Length)
702 col = node.ChildNodes;
711 ImageStyle GetImageStyle ()
713 if (ImageSet != TreeViewImageSet.Custom)
714 return (ImageStyle) imageStyles [ImageSet];
719 protected override HtmlTextWriterTag TagKey {
720 get { return HtmlTextWriterTag.Div; }
723 protected internal virtual TreeNode CreateNode ()
725 return new TreeNode (this);
728 public sealed override void DataBind ()
733 protected void SetNodeDataBound (TreeNode node, bool dataBound)
735 node.SetDataBound (dataBound);
738 protected void SetNodeDataPath (TreeNode node, string dataPath)
740 node.SetDataPath (dataPath);
743 protected void SetNodeDataItem (TreeNode node, object dataItem)
745 node.SetDataItem (dataItem);
748 protected internal override void OnInit (EventArgs e)
753 internal void SetSelectedNode (TreeNode node, bool loading)
755 if (selectedNode == node)
757 if (selectedNode != null)
758 selectedNode.SelectedFlag = false;
761 OnSelectedNodeChanged (new TreeNodeEventArgs (selectedNode));
764 internal void NotifyCheckChanged (TreeNode node)
766 OnTreeNodeCheckChanged (new TreeNodeEventArgs (node));
769 internal void NotifyExpandedChanged (TreeNode node)
771 if (node.Expanded.HasValue && node.Expanded.Value)
772 OnTreeNodeExpanded (new TreeNodeEventArgs (node));
773 else if (node.Expanded.HasValue && node.IsParentNode)
774 OnTreeNodeCollapsed (new TreeNodeEventArgs (node));
777 internal void NotifyPopulateRequired (TreeNode node)
779 OnTreeNodePopulate (new TreeNodeEventArgs (node));
782 protected override void TrackViewState()
786 base.TrackViewState();
787 if (hoverNodeStyle != null)
788 hoverNodeStyle.TrackViewState();
789 if (leafNodeStyle != null)
790 leafNodeStyle.TrackViewState();
791 if (levelStyles != null && levelStyles.Count > 0)
792 ((IStateManager)levelStyles).TrackViewState();
793 if (nodeStyle != null)
794 nodeStyle.TrackViewState();
795 if (parentNodeStyle != null)
796 parentNodeStyle.TrackViewState();
797 if (rootNodeStyle != null)
798 rootNodeStyle.TrackViewState();
799 if (selectedNodeStyle != null)
800 selectedNodeStyle.TrackViewState();
801 if (dataBindings != null)
802 ((IStateManager)dataBindings).TrackViewState ();
804 ((IStateManager)nodes).TrackViewState();;
807 protected override object SaveViewState()
809 object[] states = new object [10];
810 states[0] = base.SaveViewState();
811 states[1] = (hoverNodeStyle == null ? null : hoverNodeStyle.SaveViewState());
812 states[2] = (leafNodeStyle == null ? null : leafNodeStyle.SaveViewState());
813 states[3] = (levelStyles == null ? null : ((IStateManager)levelStyles).SaveViewState());
814 states[4] = (nodeStyle == null ? null : nodeStyle.SaveViewState());
815 states[5] = (parentNodeStyle == null ? null : parentNodeStyle.SaveViewState());
816 states[6] = (rootNodeStyle == null ? null : rootNodeStyle.SaveViewState());
817 states[7] = (selectedNodeStyle == null ? null : selectedNodeStyle.SaveViewState());
818 states[8] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
819 states[9] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
821 for (int i = states.Length - 1; i >= 0; i--) {
822 if (states [i] != null)
829 protected override void LoadViewState (object savedState)
831 if (savedState == null)
834 object [] states = (object []) savedState;
835 base.LoadViewState (states[0]);
837 if (states[1] != null)
838 HoverNodeStyle.LoadViewState (states[1]);
839 if (states[2] != null)
840 LeafNodeStyle.LoadViewState(states[2]);
841 if (states[3] != null)
842 ((IStateManager)LevelStyles).LoadViewState(states[3]);
843 if (states[4] != null)
844 NodeStyle.LoadViewState(states[4]);
845 if (states[5] != null)
846 ParentNodeStyle.LoadViewState(states[5]);
847 if (states[6] != null)
848 RootNodeStyle.LoadViewState(states[6]);
849 if (states[7] != null)
850 SelectedNodeStyle.LoadViewState(states[7]);
851 if (states[8] != null)
852 ((IStateManager)DataBindings).LoadViewState(states[8]);
853 if (states[9] != null)
854 ((IStateManager)Nodes).LoadViewState(states[9]);
857 protected virtual void RaisePostBackEvent (string eventArgument)
859 ValidateEvent (UniqueID, eventArgument);
860 string[] args = eventArgument.Split ('|');
861 TreeNode node = FindNodeByPos (args[1]);
865 if (args [0] == "sel")
866 HandleSelectEvent (node);
867 else if (args [0] == "ec")
868 HandleExpandCollapseEvent (node);
871 void HandleSelectEvent (TreeNode node)
873 switch (node.SelectAction) {
874 case TreeNodeSelectAction.Select:
877 case TreeNodeSelectAction.Expand:
880 case TreeNodeSelectAction.SelectExpand:
887 void HandleExpandCollapseEvent (TreeNode node)
889 node.ToggleExpandState ();
892 protected virtual void RaisePostDataChangedEvent ()
896 TreeNode MakeNodeTree (string[] args)
898 string[] segments = args [0].Split ('_');
899 TreeNode ret = null, node;
901 foreach (string seg in segments) {
902 int idx = Int32.Parse (seg);
903 node = new TreeNode (seg);
905 ret.ChildNodes.Add (node);
911 ret.Value = args [1].Replace ("U+007C", "|");
912 ret.ImageUrl = args [2].Replace ("U+007C", "|");
913 ret.NavigateUrl = args [3].Replace ("U+007C", "|");
914 ret.Target = args [4].Replace ("U+007C", "|");
917 NotifyPopulateRequired (ret);
922 string callbackResult;
923 protected virtual void RaiseCallbackEvent (string eventArgs)
925 string[] args = eventArgs.Split ('|');
926 RequiresDataBinding = true;
929 TreeNode node = MakeNodeTree (args);
930 ArrayList levelLines = new ArrayList ();
933 int childCount = nd.Parent != null ? nd.Parent.ChildNodes.Count : Nodes.Count;
934 levelLines.Insert (0, (nd.Index < childCount - 1) ? this : null);
938 StringWriter sw = new StringWriter ();
939 HtmlTextWriter writer = new HtmlTextWriter (sw);
940 EnsureStylesPrepared ();
942 node.Expanded = true;
943 int num = node.ChildNodes.Count;
944 for (int n=0; n<num; n++)
945 RenderNode (writer, node.ChildNodes [n], node.Depth + 1, levelLines, true, n<num-1);
947 string res = sw.ToString ();
948 callbackResult = res.Length > 0 ? res : "*";
951 protected virtual string GetCallbackResult ()
953 return callbackResult;
956 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
958 RaisePostBackEvent (eventArgument);
961 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
963 return LoadPostData (postDataKey, postCollection);
966 void IPostBackDataHandler.RaisePostDataChangedEvent ()
968 RaisePostDataChangedEvent ();
971 void ICallbackEventHandler.RaiseCallbackEvent (string eventArgs)
973 RaiseCallbackEvent (eventArgs);
976 string ICallbackEventHandler.GetCallbackResult ()
978 return GetCallbackResult ();
981 protected override ControlCollection CreateControlCollection ()
983 return new EmptyControlCollection (this);
986 protected internal override void PerformDataBinding ()
988 base.PerformDataBinding ();
989 InitializeDataBindings ();
990 HierarchicalDataSourceView data = GetData (String.Empty);
994 IHierarchicalEnumerable e = data.Select ();
995 FillBoundChildrenRecursive (e, Nodes);
998 void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, TreeNodeCollection nodeCollection)
1000 if (hEnumerable == null)
1003 foreach (object obj in hEnumerable) {
1004 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
1005 TreeNode child = new TreeNode ();
1006 nodeCollection.Add (child);
1008 OnTreeNodeDataBound (new TreeNodeEventArgs (child));
1010 if (MaxDataBindDepth >= 0 && child.Depth == MaxDataBindDepth)
1013 if (hdata == null || !hdata.HasChildren)
1016 IHierarchicalEnumerable e = hdata.GetChildren ();
1017 FillBoundChildrenRecursive (e, child.ChildNodes);
1021 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
1025 if (EnableClientScript && PopulateNodesFromClient) {
1026 string states = postCollection [ClientID + "_PopulatedStates"];
1027 if (states != null) {
1028 foreach (string id in states.Split ('|')) {
1029 if (String.IsNullOrEmpty(id))
1031 TreeNode node = FindNodeByPos (id);
1032 if (node != null && node.PopulateOnDemand && !node.Populated)
1033 node.Populated = true;
1039 UnsetCheckStates (Nodes, postCollection);
1040 SetCheckStates (postCollection);
1042 if (EnableClientScript) {
1043 string states = postCollection [ClientID + "_ExpandStates"];
1044 if (states != null) {
1045 string[] ids = states.Split ('|');
1046 UnsetExpandStates (Nodes, ids);
1047 SetExpandStates (ids);
1049 UnsetExpandStates (Nodes, new string[0]);
1055 const string _OnPreRender_Script_Preamble =
1056 "var {0} = new Object ();\n" +
1057 "{0}.treeId = {1};\n" +
1058 "{0}.uid = {2};\n" +
1059 "{0}.showImage = {3};\n";
1061 const string _OnPreRender_Script_ShowExpandCollapse =
1062 "{0}.expandImage = {1};\n" +
1063 "{0}.collapseImage = {2};\n";
1065 const string _OnPreRender_Script_ShowExpandCollapse_Populate =
1066 "{0}.noExpandImage = {1};\n";
1068 const string _OnPreRender_Script_PopulateCallback =
1069 "{0}.form = {1};\n" +
1070 "{0}.PopulateNode = function (nodeId, nodeValue, nodeImageUrl, nodeNavigateUrl, nodeTarget) {{\n" +
1071 "\t{2}.__theFormPostData = \"\";\n" +
1072 "\t{2}.__theFormPostCollection = new Array ();\n" +
1073 "\t{2}.WebForm_InitCallback ();\n" +
1074 "\tTreeView_PopulateNode (this.uid, this.treeId, nodeId, nodeValue, nodeImageUrl, nodeNavigateUrl, nodeTarget)\n}};\n";
1076 const string _OnPreRender_Script_CallbackOptions =
1077 "{0}.populateFromClient = {1};\n" +
1078 "{0}.expandAlt = {2};\n" +
1079 "{0}.collapseAlt = {3};\n";
1081 const string _OnPreRender_Script_HoverStyle =
1082 "{0}.hoverClass = {1};\n" +
1083 "{0}.hoverLinkClass = {2};\n";
1085 protected internal override void OnPreRender (EventArgs e)
1087 base.OnPreRender (e);
1091 Page.RegisterRequiresPostBack (this);
1093 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1094 string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1095 Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1099 string ctree = ClientID + "_data";
1100 StringBuilder script = new StringBuilder ();
1101 script.AppendFormat (_OnPreRender_Script_Preamble,
1103 ClientScriptManager.GetScriptLiteral (ClientID),
1104 ClientScriptManager.GetScriptLiteral (UniqueID),
1105 ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));
1107 if (ShowExpandCollapse) {
1108 ImageStyle imageStyle = GetImageStyle ();
1109 script.AppendFormat (_OnPreRender_Script_ShowExpandCollapse,
1111 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)),
1112 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)));
1114 if (PopulateNodesFromClient)
1115 script.AppendFormat (_OnPreRender_Script_ShowExpandCollapse_Populate,
1117 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)));
1121 script.AppendFormat (_OnPreRender_Script_PopulateCallback,
1124 Page.WebFormScriptReference);
1126 // Page.ClientScript.GetCallbackEventReference (
1127 // "this.uid", "nodeId",
1128 // "TreeView_PopulateCallback",
1129 // "this.treeId + \" \" + nodeId", "TreeView_PopulateCallback", false));
1131 script.AppendFormat (_OnPreRender_Script_CallbackOptions,
1133 ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient),
1134 ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)),
1135 ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1137 if (!Page.IsPostBack)
1138 SetNodesExpandedToDepthRecursive (Nodes);
1140 if (EnableClientScript) {
1141 Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1143 // Make sure the basic script infrastructure is rendered
1144 Page.ClientScript.RegisterWebFormClientScript ();
1147 if (EnableClientScript && PopulateNodesFromClient)
1148 Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1150 EnsureStylesPrepared ();
1152 if (hoverNodeStyle != null) {
1153 if (Page.Header == null)
1154 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1155 RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1156 script.AppendFormat (_OnPreRender_Script_HoverStyle,
1158 ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass),
1159 ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass));
1162 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script.ToString (), true);
1167 void EnsureStylesPrepared ()
1171 stylesPrepared = true;
1175 void PrepareStyles ()
1177 // The order in which styles are defined matters when more than one class
1178 // is assigned to an element
1179 ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1180 RegisterStyle (ControlLinkStyle);
1182 if (nodeStyle != null)
1183 RegisterStyle (NodeStyle, NodeLinkStyle);
1185 if (rootNodeStyle != null)
1186 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1188 if (parentNodeStyle != null)
1189 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1191 if (leafNodeStyle != null)
1192 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1195 if (levelStyles != null && levelStyles.Count > 0) {
1196 levelLinkStyles = new List<Style> (levelStyles.Count);
1197 foreach (Style style in levelStyles) {
1198 Style linkStyle = new Style ();
1199 levelLinkStyles.Add (linkStyle);
1200 RegisterStyle (style, linkStyle);
1204 if (selectedNodeStyle != null)
1205 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1208 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes)
1210 foreach (TreeNode node in nodes) {
1211 if (!node.Expanded.HasValue) {
1212 if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1213 node.Expanded = true;
1215 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1219 string IncrementStyleClassName ()
1221 registeredStylesCounter++;
1222 return ClientID + "_" + registeredStylesCounter;
1225 void RegisterStyle (Style baseStyle, Style linkStyle)
1227 linkStyle.CopyTextStylesFrom (baseStyle);
1228 linkStyle.BorderStyle = BorderStyle.None;
1229 linkStyle.AddCssClass (baseStyle.CssClass);
1230 baseStyle.Font.Reset ();
1231 RegisterStyle (linkStyle);
1232 RegisterStyle (baseStyle);
1235 void RegisterStyle (Style baseStyle)
1237 if (Page.Header == null)
1239 string className = IncrementStyleClassName ().Trim ('_');
1240 baseStyle.SetRegisteredCssClass (className);
1241 Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1244 string GetBindingKey (string dataMember, int depth)
1246 return dataMember + " " + depth;
1249 void InitializeDataBindings ()
1251 if (dataBindings != null && dataBindings.Count > 0) {
1252 bindings = new Hashtable ();
1253 foreach (TreeNodeBinding bin in dataBindings) {
1254 string key = GetBindingKey (bin.DataMember, bin.Depth);
1255 if (!bindings.ContainsKey(key))
1256 bindings [key] = bin;
1262 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1264 if (bindings == null)
1267 TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1271 bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1275 bin = (TreeNodeBinding) bindings [GetBindingKey (String.Empty, depth)];
1279 return (TreeNodeBinding) bindings [GetBindingKey (String.Empty, -1)];
1282 internal void DecorateNode(TreeNode node)
1287 if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1290 if (node.IsRootNode && rootNodeStyle != null) {
1291 node.ImageUrl = rootNodeStyle.ImageUrl;
1294 if (node.IsParentNode && parentNodeStyle != null) {
1295 node.ImageUrl = parentNodeStyle.ImageUrl;
1298 if (node.IsLeafNode && leafNodeStyle != null)
1299 node.ImageUrl = leafNodeStyle.ImageUrl;
1302 protected internal override void RenderContents (HtmlTextWriter writer)
1304 SiteMapDataSource siteMap = GetDataSource () as SiteMapDataSource;
1305 bool checkSitePath = IsBoundUsingDataSourceID && siteMap != null;
1307 if (checkSitePath) {
1308 IHierarchyData data = siteMap.Provider.CurrentNode;
1310 activeSiteMapPath = data.Path;
1313 ArrayList levelLines = new ArrayList ();
1314 int num = Nodes.Count;
1315 for (int n=0; n<num; n++)
1316 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1319 protected override void AddAttributesToRender(HtmlTextWriter writer)
1321 base.AddAttributesToRender (writer);
1324 public override void RenderBeginTag (HtmlTextWriter writer)
1326 string skipLinkText = SkipLinkText;
1328 if (!String.IsNullOrEmpty (skipLinkText)) {
1329 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1330 writer.RenderBeginTag (HtmlTextWriterTag.A);
1332 Image img = new Image ();
1333 ClientScriptManager csm = new ClientScriptManager (null);
1334 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1335 img.Attributes.Add ("height", "0");
1336 img.Attributes.Add ("width", "0");
1337 img.AlternateText = skipLinkText;
1338 img.Render (writer);
1340 writer.RenderEndTag ();
1342 base.RenderBeginTag (writer);
1345 public override void RenderEndTag (HtmlTextWriter writer)
1347 base.RenderEndTag (writer);
1349 if (!String.IsNullOrEmpty (SkipLinkText)) {
1350 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1351 writer.RenderBeginTag (HtmlTextWriterTag.A);
1352 writer.RenderEndTag ();
1356 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1358 if (node.PopulateOnDemand && node.HadChildrenBeforePopulating)
1359 throw new InvalidOperationException ("PopulateOnDemand cannot be set to true on a node that already has children.");
1364 bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1365 ImageStyle imageStyle = GetImageStyle ();
1366 bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1368 if (clientExpand && !renderChildNodes)
1369 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1373 if (renderChildNodes)
1374 hasChildNodes = node.ChildNodes.Count > 0;
1376 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1378 writer.AddAttribute ("cellpadding", "0", false);
1379 writer.AddAttribute ("cellspacing", "0", false);
1380 writer.AddStyleAttribute ("border-width", "0");
1381 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1383 Unit nodeSpacing = GetNodeSpacing (node);
1385 if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1386 RenderMenuItemSpacing (writer, nodeSpacing);
1388 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1390 // Vertical lines from previous levels
1392 nodeImage = GetNodeImageUrl ("i", imageStyle);
1393 for (int n=0; n<level; n++) {
1394 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1395 writer.AddStyleAttribute ("width", NodeIndent + "px");
1396 writer.AddStyleAttribute ("height", "1px");
1397 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1398 if (ShowLines && levelLines [n] != null) {
1399 writer.AddAttribute ("src", nodeImage);
1400 writer.AddAttribute (HtmlTextWriterAttribute.Alt, String.Empty, false);
1401 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1402 writer.RenderEndTag ();
1404 writer.RenderEndTag ();
1405 writer.RenderEndTag (); // TD
1408 // Node image + line
1409 bool showExpandCollapse = ShowExpandCollapse;
1410 bool showLines = ShowLines;
1411 if (showExpandCollapse || showLines) {
1412 bool buttonImage = false;
1413 string tooltip = String.Empty;
1414 string shape = String.Empty;
1417 if (hasPrevious && hasNext)
1419 else if (hasPrevious && !hasNext)
1421 else if (!hasPrevious && hasNext)
1427 if (showExpandCollapse) {
1428 if (hasChildNodes) {
1430 if (node.Expanded.HasValue && node.Expanded.Value)
1434 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1435 } else if (!showLines)
1439 if (!String.IsNullOrEmpty (shape)) {
1440 nodeImage = GetNodeImageUrl (shape, imageStyle);
1441 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1444 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1445 writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1447 writer.AddAttribute ("href", GetClientExpandEvent(node));
1448 writer.RenderBeginTag (HtmlTextWriterTag.A); // Anchor
1451 // tooltip is 'HtmlAttributeEncoded'
1452 writer.AddAttribute ("alt", tooltip);
1454 if (buttonImage && clientExpand)
1455 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1456 writer.AddAttribute ("src", nodeImage);
1458 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1459 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1460 writer.RenderEndTag ();
1463 writer.RenderEndTag (); // Anchor
1465 writer.RenderEndTag (); // TD
1471 string imageUrl = node.ImageUrl.Length > 0 ? ResolveClientUrl (node.ImageUrl) : null;
1472 if (String.IsNullOrEmpty (imageUrl) && imageStyle != null) {
1473 if (imageStyle.RootIcon != null && node.IsRootNode)
1474 imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1475 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1476 imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1477 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1478 imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1481 if (level < LevelStyles.Count && LevelStyles [level].ImageUrl != null)
1482 imageUrl = ResolveClientUrl (LevelStyles [level].ImageUrl);
1484 if (!String.IsNullOrEmpty (imageUrl)) {
1485 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1486 BeginNodeTag (writer, node, clientExpand);
1487 writer.AddAttribute ("src", imageUrl);
1488 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1489 writer.AddAttribute ("alt", node.ImageToolTip);
1490 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1491 writer.RenderEndTag (); // IMG
1492 writer.RenderEndTag (); // style tag
1493 writer.RenderEndTag (); // TD
1497 writer.AddStyleAttribute ("white-space", "nowrap");
1499 bool nodeIsSelected = node == SelectedNode && selectedNodeStyle != null;
1500 if (!nodeIsSelected && selectedNodeStyle != null) {
1501 if (!String.IsNullOrEmpty (activeSiteMapPath))
1502 nodeIsSelected = String.Compare (activeSiteMapPath,
1504 HttpRuntime.CaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == 0;
1507 AddNodeStyle (writer, node, level, nodeIsSelected);
1508 if (EnableClientScript) {
1509 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)", false);
1510 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1512 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1516 if (node.ShowCheckBoxInternal) {
1517 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1518 writer.AddAttribute ("type", "checkbox", false);
1519 writer.AddAttribute ("title", node.Text);
1520 if (node.Checked) writer.AddAttribute ("checked", "checked", false);
1521 writer.RenderBeginTag (HtmlTextWriterTag.Input); // INPUT
1522 writer.RenderEndTag (); // INPUT
1527 node.BeginRenderText (writer);
1530 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1531 AddNodeLinkStyle (writer, node, level, nodeIsSelected);
1532 BeginNodeTag (writer, node, clientExpand);
1533 writer.Write (node.Text);
1534 writer.RenderEndTag (); // style tag
1536 node.EndRenderText (writer);
1538 writer.RenderEndTag (); // TD
1540 writer.RenderEndTag (); // TR
1542 if (nodeSpacing != Unit.Empty)
1543 RenderMenuItemSpacing (writer, nodeSpacing);
1545 writer.RenderEndTag (); // TABLE
1549 if (hasChildNodes) {
1550 if (level >= levelLines.Count) {
1552 levelLines.Add (this);
1554 levelLines.Add (null);
1557 levelLines [level] = this;
1559 levelLines [level] = null;
1563 if (!(node.Expanded.HasValue && node.Expanded.Value))
1564 writer.AddStyleAttribute ("display", "none");
1566 writer.AddStyleAttribute ("display", "block");
1567 writer.AddAttribute ("id", GetNodeClientId (node, null));
1568 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1570 if (renderChildNodes) {
1571 AddChildrenPadding (writer, node);
1572 int num = node.ChildNodes.Count;
1573 for (int n=0; n<num; n++)
1574 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1576 AddChildrenPadding (writer, node);
1578 writer.RenderEndTag (); // SPAN
1579 } else if (renderChildNodes) {
1580 AddChildrenPadding (writer, node);
1581 int num = node.ChildNodes.Count;
1582 for (int n=0; n<num; n++)
1583 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1585 AddChildrenPadding (writer, node);
1590 void AddChildrenPadding (HtmlTextWriter writer, TreeNode node)
1592 int level = node.Depth;
1593 Unit cnp = Unit.Empty;
1595 if (levelStyles != null && level < levelStyles.Count)
1596 cnp = levelStyles [level].ChildNodesPadding;
1597 if (cnp.IsEmpty && nodeStyle != null)
1598 cnp = nodeStyle.ChildNodesPadding;
1601 if (cnp.IsEmpty || (value = cnp.Value) == 0 || cnp.Type != UnitType.Pixel)
1604 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1605 writer.AddAttribute ("height", ((int) value).ToString (), false);
1606 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1607 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1608 writer.RenderEndTag (); // td
1609 writer.RenderEndTag (); // tr
1610 writer.RenderEndTag (); // table
1613 void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing)
1615 writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1616 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1617 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1618 writer.RenderEndTag ();
1619 writer.RenderEndTag ();
1622 Unit GetNodeSpacing (TreeNode node)
1624 if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty)
1625 return selectedNodeStyle.NodeSpacing;
1627 if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty)
1628 return levelStyles [node.Depth].NodeSpacing;
1630 if (node.IsLeafNode) {
1631 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1632 return leafNodeStyle.NodeSpacing;
1633 } else if (node.IsRootNode) {
1634 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1635 return rootNodeStyle.NodeSpacing;
1636 } else if (node.IsParentNode) {
1637 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1638 return parentNodeStyle.NodeSpacing;
1641 if (nodeStyle != null)
1642 return nodeStyle.NodeSpacing;
1647 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1649 TreeNodeStyle style = new TreeNodeStyle ();
1650 if (Page.Header != null) {
1651 // styles are registered
1652 if (nodeStyle != null) {
1653 style.AddCssClass (nodeStyle.CssClass);
1654 style.AddCssClass (nodeStyle.RegisteredCssClass);
1656 if (node.IsLeafNode) {
1657 if (leafNodeStyle != null) {
1658 style.AddCssClass (leafNodeStyle.CssClass);
1659 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1661 } else if (node.IsRootNode) {
1662 if (rootNodeStyle != null) {
1663 style.AddCssClass (rootNodeStyle.CssClass);
1664 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1666 } else if (node.IsParentNode) {
1667 if (parentNodeStyle != null) {
1668 style.AddCssClass (parentNodeStyle.CssClass);
1669 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1672 if (levelStyles != null && levelStyles.Count > level) {
1673 style.AddCssClass (levelStyles [level].CssClass);
1674 style.AddCssClass (levelStyles [level].RegisteredCssClass);
1677 if (nodeIsSelected) {
1678 style.AddCssClass (selectedNodeStyle.CssClass);
1679 style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1682 // styles are not registered
1683 if (nodeStyle != null) {
1684 style.CopyFrom (nodeStyle);
1686 if (node.IsLeafNode) {
1687 if (leafNodeStyle != null) {
1688 style.CopyFrom (leafNodeStyle);
1690 } else if (node.IsRootNode) {
1691 if (rootNodeStyle != null) {
1692 style.CopyFrom (rootNodeStyle);
1694 } else if (node.IsParentNode) {
1695 if (parentNodeStyle != null) {
1696 style.CopyFrom (parentNodeStyle);
1699 if (levelStyles != null && levelStyles.Count > level)
1700 style.CopyFrom (levelStyles [level]);
1703 style.CopyFrom (selectedNodeStyle);
1705 style.AddAttributesToRender (writer);
1708 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1710 Style style = new Style ();
1711 if (Page.Header != null) {
1712 // styles are registered
1713 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1715 if (nodeStyle != null) {
1716 style.AddCssClass (nodeLinkStyle.CssClass);
1717 style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1720 if (levelLinkStyles != null && levelLinkStyles.Count > level) {
1721 style.AddCssClass (levelLinkStyles [level].CssClass);
1722 style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1725 if (node.IsLeafNode) {
1726 if (leafNodeStyle != null) {
1727 style.AddCssClass (leafNodeLinkStyle.CssClass);
1728 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1730 } else if (node.IsRootNode) {
1731 if (rootNodeStyle != null) {
1732 style.AddCssClass (rootNodeLinkStyle.CssClass);
1733 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1735 } else if (node.IsParentNode) {
1736 if (parentNodeStyle != null) {
1737 style.AddCssClass (parentNodeLinkStyle.CssClass);
1738 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1742 if (nodeIsSelected) {
1743 style.AddCssClass (selectedNodeLinkStyle.CssClass);
1744 style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1747 // styles are not registered
1748 style.CopyFrom (ControlLinkStyle);
1749 if (nodeStyle != null)
1750 style.CopyFrom (nodeLinkStyle);
1752 if (levelLinkStyles != null && levelLinkStyles.Count > level)
1753 style.CopyFrom (levelLinkStyles [level]);
1755 if (node.IsLeafNode) {
1756 if (node.IsLeafNode && leafNodeStyle != null) {
1757 style.CopyFrom (leafNodeLinkStyle);
1759 } else if (node.IsRootNode) {
1760 if (node.IsRootNode && rootNodeStyle != null) {
1761 style.CopyFrom (rootNodeLinkStyle);
1763 } else if (node.IsParentNode) {
1764 if (node.IsParentNode && parentNodeStyle != null) {
1765 style.CopyFrom (parentNodeLinkStyle);
1770 style.CopyFrom (selectedNodeLinkStyle);
1771 style.AlwaysRenderTextDecoration = true;
1773 style.AddAttributesToRender (writer);
1776 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1778 if(node.ToolTip.Length>0)
1779 writer.AddAttribute ("title", node.ToolTip);
1781 string navigateUrl = node.NavigateUrl;
1782 if (!String.IsNullOrEmpty (navigateUrl)) {
1783 string target = node.Target.Length > 0 ? node.Target : Target;
1785 string navUrl = ResolveClientUrl (navigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1787 string navUrl = ResolveClientUrl (navigateUrl);
1789 writer.AddAttribute ("href", navUrl);
1790 if (target.Length > 0)
1791 writer.AddAttribute ("target", target);
1792 writer.RenderBeginTag (HtmlTextWriterTag.A);
1793 } else if (node.SelectAction != TreeNodeSelectAction.None) {
1794 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1795 writer.AddAttribute ("href", GetClientExpandEvent (node));
1797 writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1798 writer.RenderBeginTag (HtmlTextWriterTag.A);
1800 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1803 string GetNodeImageToolTip (bool expand, string txt)
1806 string expandImageToolTip = ExpandImageToolTip;
1807 if (!String.IsNullOrEmpty (expandImageToolTip))
1808 return String.Format (expandImageToolTip, HttpUtility.HtmlAttributeEncode (txt));
1809 else if (txt != null)
1810 return "Expand " + HttpUtility.HtmlAttributeEncode (txt);
1812 return "Expand {0}";
1814 string collapseImageToolTip = CollapseImageToolTip;
1815 if (!String.IsNullOrEmpty (collapseImageToolTip))
1816 return String.Format (collapseImageToolTip, HttpUtility.HtmlAttributeEncode (txt));
1817 else if (txt != null)
1818 return "Collapse " + HttpUtility.HtmlAttributeEncode (txt);
1820 return "Collapse {0}";
1824 string GetNodeClientId (TreeNode node, string sufix)
1826 return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : String.Empty);
1829 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1832 if (!String.IsNullOrEmpty (LineImagesFolder))
1833 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1835 if (imageStyle != null) {
1836 if (shape == "plus") {
1837 if (!String.IsNullOrEmpty (imageStyle.Expand))
1838 return GetNodeIconUrl (imageStyle.Expand);
1839 } else if (shape == "minus") {
1840 if (!String.IsNullOrEmpty (imageStyle.Collapse))
1841 return GetNodeIconUrl (imageStyle.Collapse);
1842 } else if (shape == "noexpand") {
1843 if (!String.IsNullOrEmpty (imageStyle.NoExpand))
1844 return GetNodeIconUrl (imageStyle.NoExpand);
1847 if (shape == "plus") {
1848 if (!String.IsNullOrEmpty (ExpandImageUrl))
1849 return ResolveClientUrl (ExpandImageUrl);
1850 } else if (shape == "minus") {
1851 if (!String.IsNullOrEmpty (CollapseImageUrl))
1852 return ResolveClientUrl (CollapseImageUrl);
1853 } else if (shape == "noexpand") {
1854 if (!String.IsNullOrEmpty (NoExpandImageUrl))
1855 return ResolveClientUrl (NoExpandImageUrl);
1858 if (!String.IsNullOrEmpty (LineImagesFolder))
1859 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1861 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), "TreeView_" + shape + ".gif");
1864 string GetNodeIconUrl (string icon)
1866 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), icon + ".gif");
1869 string GetClientEvent (TreeNode node, string ev)
1871 return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path, true);
1874 string GetClientExpandEvent (TreeNode node)
1876 return String.Format ("javascript:TreeView_ToggleExpand ('{0}','{1}','{2}','{3}','{4}','{5}')",
1879 HttpUtility.HtmlAttributeEncode (node.Value).Replace ("'", "\\'").Replace ("|","U+007C"),
1880 HttpUtility.HtmlAttributeEncode (node.ImageUrl).Replace ("'", "\\'").Replace ("|","U+007c"),
1881 HttpUtility.HtmlAttributeEncode (node.NavigateUrl).Replace ("'", "\\'").Replace ("|","U+007C"),
1882 HttpUtility.HtmlAttributeEncode (node.Target).Replace ("'", "\\'").Replace ("|","U+007C"));
1885 TreeNode FindNodeByPos (string path)
1887 string[] indexes = path.Split ('_');
1888 TreeNode node = null;
1890 foreach (string index in indexes) {
1891 int i = int.Parse (index);
1893 if (i >= Nodes.Count) return null;
1896 if (i >= node.ChildNodes.Count) return null;
1897 node = node.ChildNodes [i];
1903 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1905 foreach (TreeNode node in col) {
1906 if (node.ShowCheckBoxInternal && node.Checked) {
1907 if (states == null || states [ClientID + "_cs_" + node.Path] == null)
1908 node.Checked = false;
1910 if (node.HasChildData)
1911 UnsetCheckStates (node.ChildNodes, states);
1915 void SetCheckStates (NameValueCollection states)
1920 string keyPrefix = ClientID + "_cs_";
1921 foreach (string key in states) {
1922 if (key.StartsWith (keyPrefix, StringComparison.Ordinal)) {
1923 string id = key.Substring (keyPrefix.Length);
1924 TreeNode node = FindNodeByPos (id);
1925 if (node != null && !node.Checked)
1926 node.Checked = true;
1931 void UnsetExpandStates (TreeNodeCollection col, string[] states)
1933 foreach (TreeNode node in col) {
1934 if (node.Expanded.HasValue && node.Expanded.Value) {
1935 bool expand = (Array.IndexOf (states, node.Path) != -1);
1936 if (!expand) node.Expanded = false;
1938 if (node.HasChildData)
1939 UnsetExpandStates (node.ChildNodes, states);
1943 void SetExpandStates (string[] states)
1945 foreach (string id in states) {
1946 if (String.IsNullOrEmpty (id))
1948 TreeNode node = FindNodeByPos (id);
1950 node.Expanded = true;
1954 string GetExpandStates ()
1956 StringBuilder sb = new StringBuilder ("|");
1958 foreach (TreeNode node in Nodes)
1959 GetExpandStates (sb, node);
1961 return sb.ToString ();
1964 void GetExpandStates (StringBuilder sb, TreeNode node)
1966 if (node.Expanded.HasValue && node.Expanded.Value) {
1967 sb.Append (node.Path);
1970 if (node.HasChildData) {
1971 foreach (TreeNode child in node.ChildNodes)
1972 GetExpandStates (sb, child);