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) {
169 public string Expand;
170 public string Collapse;
171 public string NoExpand;
172 public string RootIcon;
173 public string ParentIcon;
174 public string LeafIcon;
179 imageStyles [TreeViewImageSet.Arrows] = new ImageStyle ("arrow_plus", "arrow_minus", "arrow_noexpand", null, null, null);
180 imageStyles [TreeViewImageSet.BulletedList] = new ImageStyle (null, null, null, "dot_full", "dot_empty", "dot_full");
181 imageStyles [TreeViewImageSet.BulletedList2] = new ImageStyle (null, null, null, "box_full", "box_empty", "box_full");
182 imageStyles [TreeViewImageSet.BulletedList3] = new ImageStyle (null, null, null, "star_full", "star_empty", "star_full");
183 imageStyles [TreeViewImageSet.BulletedList4] = new ImageStyle (null, null, null, "star_full", "star_empty", "dots");
184 imageStyles [TreeViewImageSet.Contacts] = new ImageStyle ("TreeView_plus", "TreeView_minus", "contact", null, null, null);
185 imageStyles [TreeViewImageSet.Events] = new ImageStyle (null, null, null, "warning", "warning", "warning");
186 imageStyles [TreeViewImageSet.Inbox] = new ImageStyle (null, null, null, "inbox", "inbox", "inbox");
187 imageStyles [TreeViewImageSet.Msdn] = new ImageStyle ("box_plus", "box_minus", "box_noexpand", null, null, null);
188 imageStyles [TreeViewImageSet.Simple] = new ImageStyle (null, null, "box_full", null, null, null);
189 imageStyles [TreeViewImageSet.Simple2] = new ImageStyle (null, null, "box_empty", null, null, null);
192 imageStyles [TreeViewImageSet.News] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
193 imageStyles [TreeViewImageSet.Faq] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
194 imageStyles [TreeViewImageSet.WindowsHelp] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
195 imageStyles [TreeViewImageSet.XPFileExplorer] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", "folder", "file", "computer");
198 public event TreeNodeEventHandler TreeNodeCheckChanged {
199 add { Events.AddHandler (TreeNodeCheckChangedEvent, value); }
200 remove { Events.RemoveHandler (TreeNodeCheckChangedEvent, value); }
203 public event EventHandler SelectedNodeChanged {
204 add { Events.AddHandler (SelectedNodeChangedEvent, value); }
205 remove { Events.RemoveHandler (SelectedNodeChangedEvent, value); }
208 public event TreeNodeEventHandler TreeNodeCollapsed {
209 add { Events.AddHandler (TreeNodeCollapsedEvent, value); }
210 remove { Events.RemoveHandler (TreeNodeCollapsedEvent, value); }
213 public event TreeNodeEventHandler TreeNodeDataBound {
214 add { Events.AddHandler (TreeNodeDataBoundEvent, value); }
215 remove { Events.RemoveHandler (TreeNodeDataBoundEvent, value); }
218 public event TreeNodeEventHandler TreeNodeExpanded {
219 add { Events.AddHandler (TreeNodeExpandedEvent, value); }
220 remove { Events.RemoveHandler (TreeNodeExpandedEvent, value); }
223 public event TreeNodeEventHandler TreeNodePopulate {
224 add { Events.AddHandler (TreeNodePopulateEvent, value); }
225 remove { Events.RemoveHandler (TreeNodePopulateEvent, value); }
228 protected virtual void OnTreeNodeCheckChanged (TreeNodeEventArgs e)
230 if (Events != null) {
231 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCheckChangedEvent];
232 if (eh != null) eh (this, e);
236 protected virtual void OnSelectedNodeChanged (EventArgs e)
238 if (Events != null) {
239 EventHandler eh = (EventHandler) Events [SelectedNodeChangedEvent];
240 if (eh != null) eh (this, e);
244 protected virtual void OnTreeNodeCollapsed (TreeNodeEventArgs e)
246 if (Events != null) {
247 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCollapsedEvent];
248 if (eh != null) eh (this, e);
252 protected virtual void OnTreeNodeDataBound (TreeNodeEventArgs e)
254 if (Events != null) {
255 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeDataBoundEvent];
256 if (eh != null) eh (this, e);
260 protected virtual void OnTreeNodeExpanded (TreeNodeEventArgs e)
262 if (Events != null) {
263 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeExpandedEvent];
264 if (eh != null) eh (this, e);
268 protected virtual void OnTreeNodePopulate (TreeNodeEventArgs e)
270 if (Events != null) {
271 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodePopulateEvent];
272 if (eh != null) eh (this, e);
278 public string CollapseImageToolTip {
280 return ViewState.GetString ("CollapseImageToolTip", "Collapse {0}");
283 ViewState["CollapseImageToolTip"] = value;
287 [MonoTODO ("Implement support for this")]
288 [WebCategory ("Behavior")]
289 [WebSysDescription ("Whether the tree will automatically generate bindings.")]
290 [DefaultValue (true)]
291 public bool AutoGenerateDataBindings {
293 return ViewState.GetBool ("AutoGenerateDataBindings", true);
296 ViewState["AutoGenerateDataBindings"] = value;
301 [WebSysDescription ("The url of the image to show when a node can be collapsed.")]
303 [WebCategory ("Appearance")]
304 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
305 public string CollapseImageUrl {
307 return ViewState.GetString ("CollapseImageUrl", "");
310 ViewState["CollapseImageUrl"] = value;
314 [WebCategory ("Data")]
315 [PersistenceMode (PersistenceMode.InnerProperty)]
316 [WebSysDescription ("Bindings for tree nodes.")]
317 [Editor ("System.Web.UI.Design.WebControls.TreeViewBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
318 [DefaultValue (null)]
319 [MergablePropertyAttribute (false)]
320 public TreeNodeBindingCollection DataBindings {
322 if (dataBindings == null) {
323 dataBindings = new TreeNodeBindingCollection ();
324 if (IsTrackingViewState)
325 ((IStateManager)dataBindings).TrackViewState();
331 [WebCategory ("Behavior")]
332 [WebSysDescription ("Whether the tree view can use client-side script to expand and collapse nodes.")]
334 [DefaultValue (true)]
335 public bool EnableClientScript {
337 return ViewState.GetBool ("EnableClientScript", true);
340 ViewState["EnableClientScript"] = value;
345 [WebCategory ("Behavior")]
346 [WebSysDescription ("The initial expand depth.")]
347 [TypeConverter ("System.Web.UI.WebControls.TreeView+TreeViewExpandDepthConverter, " + Consts.AssemblySystem_Web)]
348 public int ExpandDepth {
350 return ViewState.GetInt ("ExpandDepth", -1);
353 ViewState["ExpandDepth"] = value;
358 public string ExpandImageToolTip {
360 return ViewState.GetString ("ExpandImageToolTip", "Expand {0}");
363 ViewState["ExpandImageToolTip"] = value;
369 [WebSysDescription ("The url of the image to show when a node can be expanded.")]
370 [WebCategory ("Appearance")]
371 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
372 public string ExpandImageUrl {
374 return ViewState.GetString ("ExpandImageUrl", "");
377 ViewState["ExpandImageUrl"] = value;
381 [PersistenceMode (PersistenceMode.InnerProperty)]
382 [NotifyParentProperty (true)]
383 [DefaultValue (null)]
384 [WebCategory ("Styles")]
385 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
386 public Style HoverNodeStyle {
388 if (hoverNodeStyle == null) {
389 hoverNodeStyle = new Style();
390 if (IsTrackingViewState)
391 hoverNodeStyle.TrackViewState();
393 return hoverNodeStyle;
397 [DefaultValue (TreeViewImageSet.Custom)]
398 public TreeViewImageSet ImageSet {
400 return (TreeViewImageSet)ViewState.GetInt ("ImageSet", (int)TreeViewImageSet.Custom);
403 if (!Enum.IsDefined (typeof (TreeViewImageSet), value))
404 throw new ArgumentOutOfRangeException ();
405 ViewState["ImageSet"] = value;
409 [PersistenceMode (PersistenceMode.InnerProperty)]
410 [NotifyParentProperty (true)]
411 [DefaultValue (null)]
412 [WebCategory ("Styles")]
413 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
414 public TreeNodeStyle LeafNodeStyle {
416 if (leafNodeStyle == null) {
417 leafNodeStyle = new TreeNodeStyle ();
418 if (IsTrackingViewState)
419 leafNodeStyle.TrackViewState();
421 return leafNodeStyle;
425 [DefaultValue (null)]
426 [WebCategory ("Styles")]
427 [PersistenceMode (PersistenceMode.InnerProperty)]
428 [Editor ("System.Web.UI.Design.WebControls.TreeNodeStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
429 public TreeNodeStyleCollection LevelStyles {
431 if (levelStyles == null) {
432 levelStyles = new TreeNodeStyleCollection ();
433 if (IsTrackingViewState)
434 ((IStateManager)levelStyles).TrackViewState();
441 public string LineImagesFolder {
443 return ViewState.GetString ("LineImagesFolder", "");
446 ViewState["LineImagesFolder"] = value;
451 public int MaxDataBindDepth {
453 return ViewState.GetInt ("MaxDataBindDepth", -1);
456 ViewState["MaxDataBindDepth"] = value;
461 public int NodeIndent {
463 return ViewState.GetInt ("NodeIndent", 20);
466 ViewState["NodeIndent"] = value;
470 [PersistenceMode (PersistenceMode.InnerProperty)]
471 [Editor ("System.Web.UI.Design.WebControls.TreeNodeCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
472 [DefaultValueAttribute (null)]
473 [MergablePropertyAttribute (false)]
474 public TreeNodeCollection Nodes {
477 nodes = new TreeNodeCollection (this);
478 if (IsTrackingViewState)
479 ((IStateManager)nodes).TrackViewState();
485 [PersistenceMode (PersistenceMode.InnerProperty)]
486 [NotifyParentProperty (true)]
487 [DefaultValue (null)]
488 [WebCategory ("Styles")]
489 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
490 public TreeNodeStyle NodeStyle {
492 if (nodeStyle == null) {
493 nodeStyle = new TreeNodeStyle ();
494 if (IsTrackingViewState)
495 nodeStyle.TrackViewState();
501 [DefaultValue (false)]
502 public bool NodeWrap {
504 return ViewState.GetBool ("NodeWrap", false);
507 ViewState ["NodeWrap"] = value;
513 [WebSysDescription ("The url of the image to show for leaf nodes.")]
514 [WebCategory ("Appearance")]
515 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
516 public string NoExpandImageUrl {
518 return ViewState.GetString ("NoExpandImageUrl", "");
521 ViewState ["NoExpandImageUrl"] = value;
525 [PersistenceMode (PersistenceMode.InnerProperty)]
526 [NotifyParentProperty (true)]
527 [DefaultValue (null)]
528 [WebCategory ("Styles")]
529 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
530 public TreeNodeStyle ParentNodeStyle {
532 if (parentNodeStyle == null) {
533 parentNodeStyle = new TreeNodeStyle ();
534 if (IsTrackingViewState)
535 parentNodeStyle.TrackViewState();
537 return parentNodeStyle;
542 public char PathSeparator {
544 return ViewState.GetChar ("PathSeparator", '/');
547 ViewState ["PathSeparator"] = value;
551 [DefaultValue (true)]
552 public bool PopulateNodesFromClient {
554 return ViewState.GetBool ("PopulateNodesFromClient", true);
557 ViewState ["PopulateNodesFromClient"] = value;
561 [PersistenceMode (PersistenceMode.InnerProperty)]
562 [NotifyParentProperty (true)]
563 [DefaultValue (null)]
564 [WebCategory ("Styles")]
565 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
566 public TreeNodeStyle RootNodeStyle {
568 if (rootNodeStyle == null) {
569 rootNodeStyle = new TreeNodeStyle ();
570 if (IsTrackingViewState)
571 rootNodeStyle.TrackViewState();
573 return rootNodeStyle;
577 [PersistenceMode (PersistenceMode.InnerProperty)]
578 [NotifyParentProperty (true)]
579 [DefaultValue (null)]
580 [WebCategory ("Styles")]
581 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
582 public TreeNodeStyle SelectedNodeStyle {
584 if (selectedNodeStyle == null) {
585 selectedNodeStyle = new TreeNodeStyle ();
586 if (IsTrackingViewState)
587 selectedNodeStyle.TrackViewState();
589 return selectedNodeStyle;
593 Style ControlLinkStyle {
595 if (controlLinkStyle == null) {
596 controlLinkStyle = new Style ();
597 controlLinkStyle.AlwaysRenderTextDecoration = true;
599 return controlLinkStyle;
603 Style NodeLinkStyle {
605 if (nodeLinkStyle == null) {
606 nodeLinkStyle = new Style ();
608 return nodeLinkStyle;
612 Style RootNodeLinkStyle {
614 if (rootNodeLinkStyle == null) {
615 rootNodeLinkStyle = new Style ();
617 return rootNodeLinkStyle;
621 Style ParentNodeLinkStyle {
623 if (parentNodeLinkStyle == null) {
624 parentNodeLinkStyle = new Style ();
626 return parentNodeLinkStyle;
630 Style SelectedNodeLinkStyle {
632 if (selectedNodeLinkStyle == null) {
633 selectedNodeLinkStyle = new Style ();
635 return selectedNodeLinkStyle;
639 Style LeafNodeLinkStyle {
641 if (leafNodeLinkStyle == null) {
642 leafNodeLinkStyle = new Style ();
644 return leafNodeLinkStyle;
648 Style HoverNodeLinkStyle {
650 if (hoverNodeLinkStyle == null) {
651 hoverNodeLinkStyle = new Style ();
653 return hoverNodeLinkStyle;
657 [DefaultValue (TreeNodeTypes.None)]
658 public TreeNodeTypes ShowCheckBoxes {
660 return (TreeNodeTypes)ViewState.GetInt ("ShowCheckBoxes", (int)TreeNodeTypes.None);
664 throw new ArgumentOutOfRangeException ();
665 ViewState ["ShowCheckBoxes"] = value;
669 [DefaultValue (true)]
670 public bool ShowExpandCollapse {
672 return ViewState.GetBool ("ShowExpandCollapse", true);
675 ViewState ["ShowExpandCollapse"] = value;
679 [DefaultValue (false)]
680 public bool ShowLines {
682 return ViewState.GetBool ("ShowLines", false);
685 ViewState ["ShowLines"] = value;
690 public string SkipLinkText
693 return ViewState.GetString ("SkipLinkText", "Skip Navigation Links.");
696 ViewState ["SkipLinkText"] = value;
702 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
703 public TreeNode SelectedNode {
704 get { return selectedNode; }
709 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
710 public string SelectedValue {
711 get { return selectedNode != null ? selectedNode.Value : ""; }
715 public string Target {
717 return ViewState.GetString ("Target", "");
720 ViewState ["Target"] = value;
724 [MonoTODO ("why override?")]
725 public override bool Visible
731 base.Visible = value;
736 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
737 public TreeNodeCollection CheckedNodes {
739 TreeNodeCollection col = new TreeNodeCollection ();
740 FindCheckedNodes (Nodes, col);
745 void FindCheckedNodes (TreeNodeCollection nodeList, TreeNodeCollection result)
747 foreach (TreeNode node in nodeList) {
748 if (node.Checked) result.Add (node, false);
749 FindCheckedNodes (node.ChildNodes, result);
753 public void ExpandAll ()
755 foreach (TreeNode node in Nodes)
759 public void CollapseAll ()
761 foreach (TreeNode node in Nodes)
765 public TreeNode FindNode (string valuePath)
767 if (valuePath == null) throw new ArgumentNullException ("valuePath");
768 string[] path = valuePath.Split (PathSeparator);
770 TreeNodeCollection col = Nodes;
771 bool foundBranch = true;
772 while (col.Count > 0 && foundBranch) {
774 foreach (TreeNode node in col) {
775 if (node.Value == path [n]) {
776 if (++n == path.Length) return node;
777 col = node.ChildNodes;
786 ImageStyle GetImageStyle ()
788 if (ImageSet != TreeViewImageSet.Custom)
789 return (ImageStyle) imageStyles [ImageSet];
794 protected override HtmlTextWriterTag TagKey {
795 get { return HtmlTextWriterTag.Div; }
798 protected internal virtual TreeNode CreateNode ()
800 return new TreeNode (this);
803 public sealed override void DataBind ()
808 protected void SetNodeDataBound (TreeNode node, bool dataBound)
810 node.SetDataBound (dataBound);
813 protected void SetNodeDataPath (TreeNode node, string dataPath)
815 node.SetDataPath (dataPath);
818 protected void SetNodeDataItem (TreeNode node, object dataItem)
820 node.SetDataItem (dataItem);
823 protected internal override void OnInit (EventArgs e)
828 internal void SetSelectedNode (TreeNode node, bool loading)
830 if (selectedNode == node) return;
831 if (selectedNode != null)
832 selectedNode.SelectedFlag = false;
835 OnSelectedNodeChanged (new TreeNodeEventArgs (selectedNode));
838 internal void NotifyCheckChanged (TreeNode node)
840 OnTreeNodeCheckChanged (new TreeNodeEventArgs (node));
843 internal void NotifyExpandedChanged (TreeNode node)
845 if (node.Expanded.HasValue && node.Expanded.Value)
846 OnTreeNodeExpanded (new TreeNodeEventArgs (node));
847 else if (node.Expanded.HasValue && node.IsParentNode)
848 OnTreeNodeCollapsed (new TreeNodeEventArgs (node));
851 internal void NotifyPopulateRequired (TreeNode node)
853 OnTreeNodePopulate (new TreeNodeEventArgs (node));
856 protected override void TrackViewState()
860 base.TrackViewState();
861 if (hoverNodeStyle != null) {
862 hoverNodeStyle.TrackViewState();
864 if (leafNodeStyle != null) {
865 leafNodeStyle.TrackViewState();
867 if (levelStyles != null && levelStyles.Count > 0) {
868 ((IStateManager)levelStyles).TrackViewState();
870 if (nodeStyle != null) {
871 nodeStyle.TrackViewState();
873 if (parentNodeStyle != null) {
874 parentNodeStyle.TrackViewState();
876 if (rootNodeStyle != null) {
877 rootNodeStyle.TrackViewState();
879 if (selectedNodeStyle != null) {
880 selectedNodeStyle.TrackViewState();
882 if (dataBindings != null) {
883 ((IStateManager)dataBindings).TrackViewState ();
886 ((IStateManager)nodes).TrackViewState();;
890 protected override object SaveViewState()
892 object[] states = new object [10];
893 states[0] = base.SaveViewState();
894 states[1] = (hoverNodeStyle == null ? null : hoverNodeStyle.SaveViewState());
895 states[2] = (leafNodeStyle == null ? null : leafNodeStyle.SaveViewState());
896 states[3] = (levelStyles == null ? null : ((IStateManager)levelStyles).SaveViewState());
897 states[4] = (nodeStyle == null ? null : nodeStyle.SaveViewState());
898 states[5] = (parentNodeStyle == null ? null : parentNodeStyle.SaveViewState());
899 states[6] = (rootNodeStyle == null ? null : rootNodeStyle.SaveViewState());
900 states[7] = (selectedNodeStyle == null ? null : selectedNodeStyle.SaveViewState());
901 states[8] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
902 states[9] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
904 for (int i = states.Length - 1; i >= 0; i--) {
905 if (states [i] != null)
912 protected override void LoadViewState (object savedState)
914 if (savedState == null)
917 object [] states = (object []) savedState;
918 base.LoadViewState (states[0]);
920 if (states[1] != null)
921 HoverNodeStyle.LoadViewState (states[1]);
922 if (states[2] != null)
923 LeafNodeStyle.LoadViewState(states[2]);
924 if (states[3] != null)
925 ((IStateManager)LevelStyles).LoadViewState(states[3]);
926 if (states[4] != null)
927 NodeStyle.LoadViewState(states[4]);
928 if (states[5] != null)
929 ParentNodeStyle.LoadViewState(states[5]);
930 if (states[6] != null)
931 RootNodeStyle.LoadViewState(states[6]);
932 if (states[7] != null)
933 SelectedNodeStyle.LoadViewState(states[7]);
934 if (states[8] != null)
935 ((IStateManager)DataBindings).LoadViewState(states[8]);
936 if (states[9] != null)
937 ((IStateManager)Nodes).LoadViewState(states[9]);
940 protected virtual void RaisePostBackEvent (string eventArgument)
942 ValidateEvent (UniqueID, eventArgument);
943 string[] args = eventArgument.Split ('|');
944 TreeNode node = FindNodeByPos (args[1]);
945 if (node == null) return;
947 if (args [0] == "sel")
948 HandleSelectEvent (node);
949 else if (args [0] == "ec")
950 HandleExpandCollapseEvent (node);
953 void HandleSelectEvent (TreeNode node)
955 switch (node.SelectAction) {
956 case TreeNodeSelectAction.Select:
959 case TreeNodeSelectAction.Expand:
962 case TreeNodeSelectAction.SelectExpand:
969 void HandleExpandCollapseEvent (TreeNode node)
971 node.ToggleExpandState ();
974 protected virtual void RaisePostDataChangedEvent ()
978 TreeNode MakeNodeTree (string[] args)
980 string[] segments = args [0].Split ('_');
981 TreeNode ret = null, node;
982 StringBuilder sb = new StringBuilder ();
984 foreach (string seg in segments) {
985 int idx = Int32.Parse (seg);
986 node = new TreeNode (seg);
988 ret.ChildNodes.Add (node);
994 ret.Value = args [1].Replace ("U+007C", "|");
995 ret.ImageUrl = args [2].Replace ("U+007C", "|");
996 ret.NavigateUrl = args [3].Replace ("U+007C", "|");
997 ret.Target = args [4].Replace ("U+007C", "|");
1000 NotifyPopulateRequired (ret);
1005 string callbackResult;
1006 protected virtual void RaiseCallbackEvent (string eventArgs)
1008 string[] args = eventArgs.Split ('|');
1009 RequiresDataBinding = true;
1012 TreeNode node = MakeNodeTree (args);
1013 ArrayList levelLines = new ArrayList ();
1015 while (nd != null) {
1016 int childCount = nd.Parent != null ? nd.Parent.ChildNodes.Count : Nodes.Count;
1017 levelLines.Insert (0, (nd.Index < childCount - 1) ? this : null);
1021 StringWriter sw = new StringWriter ();
1022 HtmlTextWriter writer = new HtmlTextWriter (sw);
1023 EnsureStylesPrepared ();
1025 node.Expanded = true;
1026 int num = node.ChildNodes.Count;
1027 for (int n=0; n<num; n++)
1028 RenderNode (writer, node.ChildNodes [n], node.Depth + 1, levelLines, true, n<num-1);
1030 string res = sw.ToString ();
1031 callbackResult = res.Length > 0 ? res : "*";
1034 protected virtual string GetCallbackResult ()
1036 return callbackResult;
1039 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
1041 RaisePostBackEvent (eventArgument);
1044 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
1046 return LoadPostData (postDataKey, postCollection);
1049 void IPostBackDataHandler.RaisePostDataChangedEvent ()
1051 RaisePostDataChangedEvent ();
1054 void ICallbackEventHandler.RaiseCallbackEvent (string eventArgs)
1056 RaiseCallbackEvent (eventArgs);
1059 string ICallbackEventHandler.GetCallbackResult ()
1061 return GetCallbackResult ();
1064 protected override ControlCollection CreateControlCollection ()
1066 return new EmptyControlCollection (this);
1069 protected internal override void PerformDataBinding ()
1071 base.PerformDataBinding ();
1072 InitializeDataBindings ();
1073 HierarchicalDataSourceView data = GetData ("");
1077 IHierarchicalEnumerable e = data.Select ();
1078 FillBoundChildrenRecursive (e, Nodes);
1081 void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, TreeNodeCollection nodeCollection)
1083 if (hEnumerable == null)
1086 foreach (object obj in hEnumerable) {
1087 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
1088 TreeNode child = new TreeNode ();
1089 nodeCollection.Add (child);
1091 OnTreeNodeDataBound (new TreeNodeEventArgs (child));
1093 if (MaxDataBindDepth >= 0 && child.Depth == MaxDataBindDepth)
1096 if (hdata == null || !hdata.HasChildren)
1099 IHierarchicalEnumerable e = hdata.GetChildren ();
1100 FillBoundChildrenRecursive (e, child.ChildNodes);
1104 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
1108 if (EnableClientScript && PopulateNodesFromClient) {
1109 string states = postCollection [ClientID + "_PopulatedStates"];
1110 if (states != null) {
1111 foreach (string id in states.Split ('|')) {
1112 if (String.IsNullOrEmpty(id))
1114 TreeNode node = FindNodeByPos (id);
1115 if (node != null && node.PopulateOnDemand && !node.Populated)
1116 node.Populated = true;
1122 UnsetCheckStates (Nodes, postCollection);
1123 SetCheckStates (postCollection);
1125 if (EnableClientScript) {
1126 string states = postCollection [ClientID + "_ExpandStates"];
1127 if (states != null) {
1128 string[] ids = states.Split ('|');
1129 UnsetExpandStates (Nodes, ids);
1130 SetExpandStates (ids);
1133 UnsetExpandStates (Nodes, new string[0]);
1139 const string _OnPreRender_Script_Preamble =
1140 "var {0} = new Object ();\n" +
1141 "{0}.treeId = {1};\n" +
1142 "{0}.uid = {2};\n" +
1143 "{0}.showImage = {3};\n";
1145 const string _OnPreRender_Script_ShowExpandCollapse =
1146 "{0}.expandImage = {1};\n" +
1147 "{0}.collapseImage = {2};\n";
1149 const string _OnPreRender_Script_ShowExpandCollapse_Populate =
1150 "{0}.noExpandImage = {1};\n";
1152 const string _OnPreRender_Script_PopulateCallback =
1153 "{0}.form = {1};\n" +
1154 "{0}.PopulateNode = function (nodeId, nodeValue, nodeImageUrl, nodeNavigateUrl, nodeTarget) {{\n" +
1155 "\t{2}.__theFormPostData = \"\";\n" +
1156 "\t{2}.__theFormPostCollection = new Array ();\n" +
1157 "\t{2}.WebForm_InitCallback ();\n" +
1158 "\tTreeView_PopulateNode (this.uid, this.treeId, nodeId, nodeValue, nodeImageUrl, nodeNavigateUrl, nodeTarget)\n}};\n";
1160 const string _OnPreRender_Script_CallbackOptions =
1161 "{0}.populateFromClient = {1};\n" +
1162 "{0}.expandAlt = {2};\n" +
1163 "{0}.collapseAlt = {3};\n";
1165 const string _OnPreRender_Script_HoverStyle =
1166 "{0}.hoverClass = {1};\n" +
1167 "{0}.hoverLinkClass = {2};\n";
1169 protected internal override void OnPreRender (EventArgs e)
1171 base.OnPreRender (e);
1175 Page.RegisterRequiresPostBack (this);
1177 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1178 string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1179 Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1183 string ctree = ClientID + "_data";
1184 StringBuilder script = new StringBuilder ();
1185 script.AppendFormat (_OnPreRender_Script_Preamble,
1187 ClientScriptManager.GetScriptLiteral (ClientID),
1188 ClientScriptManager.GetScriptLiteral (UniqueID),
1189 ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));
1191 if (ShowExpandCollapse) {
1192 ImageStyle imageStyle = GetImageStyle ();
1193 script.AppendFormat (_OnPreRender_Script_ShowExpandCollapse,
1195 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)),
1196 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)));
1198 if (PopulateNodesFromClient)
1199 script.AppendFormat (_OnPreRender_Script_ShowExpandCollapse_Populate,
1201 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)));
1205 script.AppendFormat (_OnPreRender_Script_PopulateCallback,
1208 Page.WebFormScriptReference);
1210 // Page.ClientScript.GetCallbackEventReference (
1211 // "this.uid", "nodeId",
1212 // "TreeView_PopulateCallback",
1213 // "this.treeId + \" \" + nodeId", "TreeView_PopulateCallback", false));
1215 script.AppendFormat (_OnPreRender_Script_CallbackOptions,
1217 ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient),
1218 ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)),
1219 ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1221 if (!Page.IsPostBack) {
1222 SetNodesExpandedToDepthRecursive (Nodes);
1225 if (EnableClientScript) {
1226 Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1228 // Make sure the basic script infrastructure is rendered
1229 Page.ClientScript.RegisterWebFormClientScript ();
1232 if (EnableClientScript && PopulateNodesFromClient) {
1233 Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1236 EnsureStylesPrepared ();
1238 if (hoverNodeStyle != null) {
1239 if (Page.Header == null)
1240 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1241 RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1242 script.AppendFormat (_OnPreRender_Script_HoverStyle,
1244 ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass),
1245 ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass));
1248 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script.ToString (), true);
1253 void EnsureStylesPrepared () {
1256 stylesPrepared = true;
1260 void PrepareStyles () {
1261 // The order in which styles are defined matters when more than one class
1262 // is assigned to an element
1263 ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1264 RegisterStyle (ControlLinkStyle);
1266 if (nodeStyle != null)
1267 RegisterStyle (NodeStyle, NodeLinkStyle);
1269 if (rootNodeStyle != null)
1270 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1272 if (parentNodeStyle != null)
1273 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1275 if (leafNodeStyle != null)
1276 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1279 if (levelStyles != null && levelStyles.Count > 0) {
1280 levelLinkStyles = new List<Style> (levelStyles.Count);
1281 foreach (Style style in levelStyles) {
1282 Style linkStyle = new Style ();
1283 levelLinkStyles.Add (linkStyle);
1284 RegisterStyle (style, linkStyle);
1288 if (selectedNodeStyle != null)
1289 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1292 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes) {
1293 foreach (TreeNode node in nodes) {
1294 if (!node.Expanded.HasValue) {
1295 if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1296 node.Expanded = true;
1298 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1302 string IncrementStyleClassName () {
1303 registeredStylesCounter++;
1304 return ClientID + "_" + registeredStylesCounter;
1307 void RegisterStyle (Style baseStyle, Style linkStyle) {
1308 linkStyle.CopyTextStylesFrom (baseStyle);
1309 linkStyle.BorderStyle = BorderStyle.None;
1310 baseStyle.Font.Reset ();
1311 RegisterStyle (linkStyle);
1312 RegisterStyle (baseStyle);
1315 void RegisterStyle (Style baseStyle) {
1316 if (Page.Header == null)
1318 string className = IncrementStyleClassName ().Trim ('_');
1319 baseStyle.SetRegisteredCssClass (className);
1320 Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1323 string GetBindingKey (string dataMember, int depth)
1325 return dataMember + " " + depth;
1328 void InitializeDataBindings () {
1329 if (dataBindings != null && dataBindings.Count > 0) {
1330 bindings = new Hashtable ();
1331 foreach (TreeNodeBinding bin in dataBindings) {
1332 string key = GetBindingKey (bin.DataMember, bin.Depth);
1333 if (!bindings.ContainsKey(key))
1334 bindings [key] = bin;
1341 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1343 if (bindings == null)
1346 TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1347 if (bin != null) return bin;
1349 bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1350 if (bin != null) return bin;
1352 bin = (TreeNodeBinding) bindings [GetBindingKey ("", depth)];
1353 if (bin != null) return bin;
1355 return (TreeNodeBinding) bindings [GetBindingKey ("", -1)];
1358 internal void DecorateNode(TreeNode node)
1363 if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1366 if (node.IsRootNode && rootNodeStyle != null) {
1367 node.ImageUrl = rootNodeStyle.ImageUrl;
1370 if (node.IsParentNode && parentNodeStyle != null) {
1371 node.ImageUrl = parentNodeStyle.ImageUrl;
1374 if (node.IsLeafNode && leafNodeStyle != null)
1375 node.ImageUrl = leafNodeStyle.ImageUrl;
1378 protected internal override void RenderContents (HtmlTextWriter writer)
1380 SiteMapDataSource siteMap = GetDataSource () as SiteMapDataSource;
1381 bool checkSitePath = IsBoundUsingDataSourceID && siteMap != null;
1383 if (checkSitePath) {
1384 IHierarchyData data = siteMap.Provider.CurrentNode;
1386 activeSiteMapPath = data.Path;
1389 ArrayList levelLines = new ArrayList ();
1390 int num = Nodes.Count;
1391 for (int n=0; n<num; n++)
1392 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1395 protected override void AddAttributesToRender(HtmlTextWriter writer)
1397 base.AddAttributesToRender (writer);
1400 public override void RenderBeginTag (HtmlTextWriter writer)
1402 if (SkipLinkText != "") {
1403 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1404 writer.RenderBeginTag (HtmlTextWriterTag.A);
1406 Image img = new Image ();
1407 ClientScriptManager csm = new ClientScriptManager (null);
1408 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1409 img.Attributes.Add ("height", "0");
1410 img.Attributes.Add ("width", "0");
1411 img.AlternateText = SkipLinkText;
1412 img.Render (writer);
1414 writer.RenderEndTag ();
1416 base.RenderBeginTag (writer);
1419 public override void RenderEndTag (HtmlTextWriter writer)
1421 base.RenderEndTag (writer);
1423 if (SkipLinkText != "") {
1424 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1425 writer.RenderBeginTag (HtmlTextWriterTag.A);
1426 writer.RenderEndTag ();
1430 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1435 bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1436 ImageStyle imageStyle = GetImageStyle ();
1437 bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1439 if (clientExpand && !renderChildNodes)
1440 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1444 if (renderChildNodes)
1445 hasChildNodes = node.ChildNodes.Count > 0;
1447 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1449 writer.AddAttribute ("cellpadding", "0", false);
1450 writer.AddAttribute ("cellspacing", "0", false);
1451 writer.AddStyleAttribute ("border-width", "0");
1452 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1454 Unit nodeSpacing = GetNodeSpacing (node);
1456 if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1457 RenderMenuItemSpacing (writer, nodeSpacing);
1459 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1461 // Vertical lines from previous levels
1463 nodeImage = GetNodeImageUrl ("i", imageStyle);
1464 for (int n=0; n<level; n++) {
1465 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1466 writer.AddStyleAttribute ("width", NodeIndent + "px");
1467 writer.AddStyleAttribute ("height", "1px");
1468 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1469 if (ShowLines && levelLines [n] != null) {
1470 writer.AddAttribute ("src", nodeImage);
1471 writer.AddAttribute (HtmlTextWriterAttribute.Alt, "", false);
1472 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1473 writer.RenderEndTag ();
1475 writer.RenderEndTag ();
1476 writer.RenderEndTag (); // TD
1479 // Node image + line
1481 if (ShowExpandCollapse || ShowLines) {
1482 bool buttonImage = false;
1483 string tooltip = "";
1487 if (hasPrevious && hasNext) shape = "t";
1488 else if (hasPrevious && !hasNext) shape = "l";
1489 else if (!hasPrevious && hasNext) shape = "r";
1490 else shape = "dash";
1493 if (ShowExpandCollapse) {
1494 if (hasChildNodes) {
1496 if (node.Expanded.HasValue && node.Expanded.Value) shape += "minus";
1497 else shape += "plus";
1498 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1499 } else if (!ShowLines)
1504 nodeImage = GetNodeImageUrl (shape, imageStyle);
1505 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1508 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1509 writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1511 writer.AddAttribute ("href", GetClientExpandEvent(node));
1512 writer.RenderBeginTag (HtmlTextWriterTag.A); // Anchor
1515 // tooltip is 'HtmlAttributeEncoded'
1516 writer.AddAttribute ("alt", tooltip);
1518 if (buttonImage && clientExpand)
1519 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1520 writer.AddAttribute ("src", nodeImage);
1522 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1523 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1524 writer.RenderEndTag ();
1527 writer.RenderEndTag (); // Anchor
1529 writer.RenderEndTag (); // TD
1535 string imageUrl = node.ImageUrl.Length > 0 ? ResolveClientUrl (node.ImageUrl) : null;
1536 if (String.IsNullOrEmpty (imageUrl) && imageStyle != null) {
1537 if (imageStyle.RootIcon != null && node.IsRootNode)
1538 imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1539 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1540 imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1541 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1542 imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1545 if (level < LevelStyles.Count && LevelStyles [level].ImageUrl != null)
1546 imageUrl = ResolveClientUrl (LevelStyles [level].ImageUrl);
1548 if (!String.IsNullOrEmpty (imageUrl)) {
1549 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1550 BeginNodeTag (writer, node, clientExpand);
1551 writer.AddAttribute ("src", imageUrl);
1552 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1553 writer.AddAttribute ("alt", node.ImageToolTip);
1554 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1555 writer.RenderEndTag (); // IMG
1556 writer.RenderEndTag (); // style tag
1557 writer.RenderEndTag (); // TD
1561 writer.AddStyleAttribute ("white-space", "nowrap");
1563 bool nodeIsSelected = node == SelectedNode && selectedNodeStyle != null;
1564 if (!nodeIsSelected && selectedNodeStyle != null) {
1565 if (!String.IsNullOrEmpty (activeSiteMapPath))
1566 nodeIsSelected = String.Compare (activeSiteMapPath,
1568 HttpRuntime.CaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == 0;
1571 AddNodeStyle (writer, node, level, nodeIsSelected);
1572 if (EnableClientScript) {
1573 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)", false);
1574 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1576 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1580 if (node.ShowCheckBoxInternal) {
1581 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1582 writer.AddAttribute ("type", "checkbox", false);
1583 writer.AddAttribute ("title", node.Text);
1584 if (node.Checked) writer.AddAttribute ("checked", "checked", false);
1585 writer.RenderBeginTag (HtmlTextWriterTag.Input); // INPUT
1586 writer.RenderEndTag (); // INPUT
1591 node.BeginRenderText (writer);
1594 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1595 AddNodeLinkStyle (writer, node, level, nodeIsSelected);
1596 BeginNodeTag (writer, node, clientExpand);
1597 writer.Write (node.Text);
1598 writer.RenderEndTag (); // style tag
1600 node.EndRenderText (writer);
1602 writer.RenderEndTag (); // TD
1604 writer.RenderEndTag (); // TR
1606 if (nodeSpacing != Unit.Empty)
1607 RenderMenuItemSpacing (writer, nodeSpacing);
1609 writer.RenderEndTag (); // TABLE
1613 if (hasChildNodes) {
1614 if (level >= levelLines.Count) {
1616 levelLines.Add (this);
1618 levelLines.Add (null);
1621 levelLines [level] = this;
1623 levelLines [level] = null;
1627 if (!(node.Expanded.HasValue && node.Expanded.Value))
1628 writer.AddStyleAttribute ("display", "none");
1630 writer.AddStyleAttribute ("display", "block");
1631 writer.AddAttribute ("id", GetNodeClientId (node, null));
1632 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1634 if (renderChildNodes) {
1635 AddChildrenPadding (writer, node);
1636 int num = node.ChildNodes.Count;
1637 for (int n=0; n<num; n++)
1638 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1640 AddChildrenPadding (writer, node);
1642 writer.RenderEndTag (); // SPAN
1643 } else if (renderChildNodes) {
1644 AddChildrenPadding (writer, node);
1645 int num = node.ChildNodes.Count;
1646 for (int n=0; n<num; n++)
1647 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1649 AddChildrenPadding (writer, node);
1654 void AddChildrenPadding (HtmlTextWriter writer, TreeNode node)
1656 int level = node.Depth;
1657 Unit cnp = Unit.Empty;
1659 if (levelStyles != null && level < levelStyles.Count)
1660 cnp = levelStyles [level].ChildNodesPadding;
1661 if (cnp.IsEmpty && nodeStyle != null)
1662 cnp = nodeStyle.ChildNodesPadding;
1665 if (cnp.IsEmpty || (value = cnp.Value) == 0 || cnp.Type != UnitType.Pixel)
1668 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1669 writer.AddAttribute ("height", ((int) value).ToString (), false);
1670 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1671 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1672 writer.RenderEndTag (); // td
1673 writer.RenderEndTag (); // tr
1674 writer.RenderEndTag (); // table
1677 void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing) {
1678 writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1679 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1680 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1681 writer.RenderEndTag ();
1682 writer.RenderEndTag ();
1685 Unit GetNodeSpacing (TreeNode node) {
1686 if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty) {
1687 return selectedNodeStyle.NodeSpacing;
1690 if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty) {
1691 return levelStyles [node.Depth].NodeSpacing;
1694 if (node.IsLeafNode) {
1695 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1696 return leafNodeStyle.NodeSpacing;
1698 else if (node.IsRootNode) {
1699 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1700 return rootNodeStyle.NodeSpacing;
1702 else if (node.IsParentNode) {
1703 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1704 return parentNodeStyle.NodeSpacing;
1707 if (nodeStyle != null)
1708 return nodeStyle.NodeSpacing;
1713 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1715 TreeNodeStyle style = new TreeNodeStyle ();
1716 if (Page.Header != null) {
1717 // styles are registered
1718 if (nodeStyle != null) {
1719 style.AddCssClass (nodeStyle.CssClass);
1720 style.AddCssClass (nodeStyle.RegisteredCssClass);
1722 if (node.IsLeafNode) {
1723 if (leafNodeStyle != null) {
1724 style.AddCssClass (leafNodeStyle.CssClass);
1725 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1727 } else if (node.IsRootNode) {
1728 if (rootNodeStyle != null) {
1729 style.AddCssClass (rootNodeStyle.CssClass);
1730 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1732 } else if (node.IsParentNode) {
1733 if (parentNodeStyle != null) {
1734 style.AddCssClass (parentNodeStyle.CssClass);
1735 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1738 if (levelStyles != null && levelStyles.Count > level) {
1739 style.AddCssClass (levelStyles [level].CssClass);
1740 style.AddCssClass (levelStyles [level].RegisteredCssClass);
1743 if (nodeIsSelected) {
1744 style.AddCssClass (selectedNodeStyle.CssClass);
1745 style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1748 // styles are not registered
1749 if (nodeStyle != null) {
1750 style.CopyFrom (nodeStyle);
1752 if (node.IsLeafNode) {
1753 if (leafNodeStyle != null) {
1754 style.CopyFrom (leafNodeStyle);
1757 else if (node.IsRootNode) {
1758 if (rootNodeStyle != null) {
1759 style.CopyFrom (rootNodeStyle);
1762 else if (node.IsParentNode) {
1763 if (parentNodeStyle != null) {
1764 style.CopyFrom (parentNodeStyle);
1767 if (levelStyles != null && levelStyles.Count > level) {
1768 style.CopyFrom (levelStyles [level]);
1771 if (nodeIsSelected) {
1772 style.CopyFrom (selectedNodeStyle);
1775 style.AddAttributesToRender (writer);
1778 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1780 Style style = new Style ();
1781 if (Page.Header != null) {
1782 // styles are registered
1783 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1785 if (nodeStyle != null) {
1786 style.AddCssClass (nodeLinkStyle.CssClass);
1787 style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1789 if (node.IsLeafNode) {
1790 if (leafNodeStyle != null) {
1791 style.AddCssClass (leafNodeLinkStyle.CssClass);
1792 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1795 else if (node.IsRootNode) {
1796 if (rootNodeStyle != null) {
1797 style.AddCssClass (rootNodeLinkStyle.CssClass);
1798 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1801 else if (node.IsParentNode) {
1802 if (parentNodeStyle != null) {
1803 style.AddCssClass (parentNodeLinkStyle.CssClass);
1804 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1807 if (levelStyles != null && levelStyles.Count > level) {
1808 style.AddCssClass (levelLinkStyles [level].CssClass);
1809 style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1811 if (nodeIsSelected) {
1812 style.AddCssClass (selectedNodeLinkStyle.CssClass);
1813 style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1817 // styles are not registered
1818 style.CopyFrom (ControlLinkStyle);
1819 if (nodeStyle != null) {
1820 style.CopyFrom (nodeLinkStyle);
1822 if (node.IsLeafNode) {
1823 if (node.IsLeafNode && leafNodeStyle != null) {
1824 style.CopyFrom (leafNodeLinkStyle);
1827 else if (node.IsRootNode) {
1828 if (node.IsRootNode && rootNodeStyle != null) {
1829 style.CopyFrom (rootNodeLinkStyle);
1832 else if (node.IsParentNode) {
1833 if (node.IsParentNode && parentNodeStyle != null) {
1834 style.CopyFrom (parentNodeLinkStyle);
1837 if (levelStyles != null && levelStyles.Count > level) {
1838 style.CopyFrom (levelLinkStyles [level]);
1840 if (nodeIsSelected) {
1841 style.CopyFrom (selectedNodeLinkStyle);
1843 style.AlwaysRenderTextDecoration = true;
1845 style.AddAttributesToRender (writer);
1848 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1850 if(node.ToolTip.Length>0)
1851 writer.AddAttribute ("title", node.ToolTip);
1853 if (node.NavigateUrl != "") {
1854 string target = node.Target.Length > 0 ? node.Target : Target;
1856 string navUrl = ResolveClientUrl (node.NavigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1858 string navUrl = ResolveClientUrl (node.NavigateUrl);
1860 writer.AddAttribute ("href", navUrl);
1861 if (target.Length > 0)
1862 writer.AddAttribute ("target", target);
1863 writer.RenderBeginTag (HtmlTextWriterTag.A);
1865 else if (node.SelectAction != TreeNodeSelectAction.None) {
1866 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1867 writer.AddAttribute ("href", GetClientExpandEvent (node));
1869 writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1870 writer.RenderBeginTag (HtmlTextWriterTag.A);
1873 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1876 string GetNodeImageToolTip (bool expand, string txt) {
1878 if (ExpandImageToolTip != "")
1879 return String.Format (ExpandImageToolTip, HttpUtility.HtmlAttributeEncode (txt));
1880 else if (txt != null)
1881 return "Expand " + HttpUtility.HtmlAttributeEncode (txt);
1883 return "Expand {0}";
1885 if (CollapseImageToolTip != "")
1886 return String.Format (CollapseImageToolTip, HttpUtility.HtmlAttributeEncode (txt));
1887 else if (txt != null)
1888 return "Collapse " + HttpUtility.HtmlAttributeEncode (txt);
1890 return "Collapse {0}";
1894 string GetNodeClientId (TreeNode node, string sufix)
1896 return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : "");
1899 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1902 if (!String.IsNullOrEmpty (LineImagesFolder))
1903 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1905 if (imageStyle != null) {
1906 if (shape == "plus") {
1907 if (!String.IsNullOrEmpty (imageStyle.Expand))
1908 return GetNodeIconUrl (imageStyle.Expand);
1910 else if (shape == "minus") {
1911 if (!String.IsNullOrEmpty (imageStyle.Collapse))
1912 return GetNodeIconUrl (imageStyle.Collapse);
1914 else if (shape == "noexpand") {
1915 if (!String.IsNullOrEmpty (imageStyle.NoExpand))
1916 return GetNodeIconUrl (imageStyle.NoExpand);
1920 if (shape == "plus") {
1921 if (!String.IsNullOrEmpty (ExpandImageUrl))
1922 return ResolveClientUrl (ExpandImageUrl);
1924 else if (shape == "minus") {
1925 if (!String.IsNullOrEmpty (CollapseImageUrl))
1926 return ResolveClientUrl (CollapseImageUrl);
1928 else if (shape == "noexpand") {
1929 if (!String.IsNullOrEmpty (NoExpandImageUrl))
1930 return ResolveClientUrl (NoExpandImageUrl);
1933 if (!String.IsNullOrEmpty (LineImagesFolder))
1934 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1936 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), "TreeView_" + shape + ".gif");
1939 string GetNodeIconUrl (string icon)
1941 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), icon + ".gif");
1944 string GetClientEvent (TreeNode node, string ev)
1946 return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path, true);
1949 string GetClientExpandEvent (TreeNode node)
1951 return String.Format ("javascript:TreeView_ToggleExpand ('{0}','{1}','{2}','{3}','{4}','{5}')",
1954 HttpUtility.HtmlAttributeEncode (node.Value).Replace ("'", "\\'").Replace ("|","U+007C"),
1955 HttpUtility.HtmlAttributeEncode (node.ImageUrl).Replace ("'", "\\'").Replace ("|","U+007c"),
1956 HttpUtility.HtmlAttributeEncode (node.NavigateUrl).Replace ("'", "\\'").Replace ("|","U+007C"),
1957 HttpUtility.HtmlAttributeEncode (node.Target).Replace ("'", "\\'").Replace ("|","U+007C"));
1960 TreeNode FindNodeByPos (string path)
1962 string[] indexes = path.Split ('_');
1963 TreeNode node = null;
1965 foreach (string index in indexes) {
1966 int i = int.Parse (index);
1968 if (i >= Nodes.Count) return null;
1971 if (i >= node.ChildNodes.Count) return null;
1972 node = node.ChildNodes [i];
1978 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1980 foreach (TreeNode node in col) {
1981 if (node.ShowCheckBoxInternal && node.Checked) {
1982 if (states == null || states [ClientID + "_cs_" + node.Path] == null)
1983 node.Checked = false;
1985 if (node.HasChildData)
1986 UnsetCheckStates (node.ChildNodes, states);
1990 void SetCheckStates (NameValueCollection states)
1995 string keyPrefix = ClientID + "_cs_";
1996 foreach (string key in states) {
1997 if (key.StartsWith (keyPrefix, StringComparison.Ordinal)) {
1998 string id = key.Substring (keyPrefix.Length);
1999 TreeNode node = FindNodeByPos (id);
2000 if (node != null && !node.Checked)
2001 node.Checked = true;
2006 void UnsetExpandStates (TreeNodeCollection col, string[] states)
2008 foreach (TreeNode node in col) {
2009 if (node.Expanded.HasValue && node.Expanded.Value) {
2010 bool expand = (Array.IndexOf (states, node.Path) != -1);
2011 if (!expand) node.Expanded = false;
2013 if (node.HasChildData)
2014 UnsetExpandStates (node.ChildNodes, states);
2018 void SetExpandStates (string[] states)
2020 foreach (string id in states) {
2021 if (id == null || id == "") continue;
2022 TreeNode node = FindNodeByPos (id);
2024 node.Expanded = true;
2028 string GetExpandStates ()
2030 StringBuilder sb = new StringBuilder ("|");
2032 foreach (TreeNode node in Nodes)
2033 GetExpandStates (sb, node);
2035 return sb.ToString ();
2038 void GetExpandStates (StringBuilder sb, TreeNode node)
2040 if (node.Expanded.HasValue && node.Expanded.Value) {
2041 sb.Append (node.Path);
2044 if (node.HasChildData) {
2045 foreach (TreeNode child in node.ChildNodes)
2046 GetExpandStates (sb, child);