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;
43 namespace System.Web.UI.WebControls
46 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
49 [SupportsEventValidation]
50 [ControlValueProperty ("SelectedValue")]
51 [DefaultEvent ("SelectedNodeChanged")]
52 [Designer ("System.Web.UI.Design.WebControls.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
53 public class TreeView: HierarchicalDataBoundControl, IPostBackEventHandler, IPostBackDataHandler, ICallbackEventHandler
55 string activeSiteMapPath;
58 TreeNodeStyle leafNodeStyle;
59 TreeNodeStyle nodeStyle;
60 TreeNodeStyle parentNodeStyle;
61 TreeNodeStyle rootNodeStyle;
62 TreeNodeStyle selectedNodeStyle;
64 TreeNodeStyleCollection levelStyles;
65 TreeNodeCollection nodes;
66 TreeNodeBindingCollection dataBindings;
68 TreeNode selectedNode;
71 int registeredStylesCounter = -1;
72 List<Style> levelLinkStyles;
73 Style controlLinkStyle;
75 Style rootNodeLinkStyle;
76 Style parentNodeLinkStyle;
77 Style leafNodeLinkStyle;
78 Style selectedNodeLinkStyle;
79 Style hoverNodeLinkStyle;
81 static readonly object TreeNodeCheckChangedEvent = new object();
82 static readonly object SelectedNodeChangedEvent = new object();
83 static readonly object TreeNodeCollapsedEvent = new object();
84 static readonly object TreeNodeDataBoundEvent = new object();
85 static readonly object TreeNodeExpandedEvent = new object();
86 static readonly object TreeNodePopulateEvent = new object();
88 static Hashtable imageStyles = new Hashtable ();
90 class TreeViewExpandDepthConverter : TypeConverter
92 public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType)
94 if (sourceType == typeof (string) || sourceType == typeof (int))
97 return base.CanConvertFrom (context, sourceType);
100 public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
102 if (destinationType == typeof (string) || destinationType == typeof (int))
105 return base.CanConvertTo (context, destinationType);
108 public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
110 if (destinationType != typeof (int) && destinationType != typeof (string))
111 return base.ConvertTo (context, culture, value, destinationType);
113 if (value is string) {
114 if (destinationType == typeof (int)) {
115 if (String.Compare ("FullyExpand", (string)value, StringComparison.OrdinalIgnoreCase) == 0)
119 return Int32.Parse ((string)value);
120 } catch (Exception) {
127 int val = (int)value;
128 if (destinationType == typeof (string)) {
130 return "FullyExpand";
131 return val.ToString ();
137 public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value)
139 if (!(value is string) && !(value is int))
140 return base.ConvertFrom (context, culture, value);
142 if (value is string) {
143 if (String.Compare ("FullyExpand", (string)value, StringComparison.OrdinalIgnoreCase) == 0)
147 return Int32.Parse ((string)value);
148 } catch (Exception) {
159 public ImageStyle (string expand, string collapse, string noExpand, string icon, string iconLeaf, string iconRoot) {
168 public string Expand;
169 public string Collapse;
170 public string NoExpand;
171 public string RootIcon;
172 public string ParentIcon;
173 public string LeafIcon;
178 imageStyles [TreeViewImageSet.Arrows] = new ImageStyle ("arrow_plus", "arrow_minus", "arrow_noexpand", null, null, null);
179 imageStyles [TreeViewImageSet.BulletedList] = new ImageStyle (null, null, null, "dot_full", "dot_empty", "dot_full");
180 imageStyles [TreeViewImageSet.BulletedList2] = new ImageStyle (null, null, null, "box_full", "box_empty", "box_full");
181 imageStyles [TreeViewImageSet.BulletedList3] = new ImageStyle (null, null, null, "star_full", "star_empty", "star_full");
182 imageStyles [TreeViewImageSet.BulletedList4] = new ImageStyle (null, null, null, "star_full", "star_empty", "dots");
183 imageStyles [TreeViewImageSet.Contacts] = new ImageStyle ("TreeView_plus", "TreeView_minus", "contact", null, null, null);
184 imageStyles [TreeViewImageSet.Events] = new ImageStyle (null, null, null, "warning", "warning", "warning");
185 imageStyles [TreeViewImageSet.Inbox] = new ImageStyle (null, null, null, "inbox", "inbox", "inbox");
186 imageStyles [TreeViewImageSet.Msdn] = new ImageStyle ("box_plus", "box_minus", "box_noexpand", null, null, null);
187 imageStyles [TreeViewImageSet.Simple] = new ImageStyle (null, null, "box_full", null, null, null);
188 imageStyles [TreeViewImageSet.Simple2] = new ImageStyle (null, null, "box_empty", null, null, null);
191 imageStyles [TreeViewImageSet.News] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
192 imageStyles [TreeViewImageSet.Faq] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
193 imageStyles [TreeViewImageSet.WindowsHelp] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
194 imageStyles [TreeViewImageSet.XPFileExplorer] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", "folder", "file", "computer");
197 public event TreeNodeEventHandler TreeNodeCheckChanged {
198 add { Events.AddHandler (TreeNodeCheckChangedEvent, value); }
199 remove { Events.RemoveHandler (TreeNodeCheckChangedEvent, value); }
202 public event EventHandler SelectedNodeChanged {
203 add { Events.AddHandler (SelectedNodeChangedEvent, value); }
204 remove { Events.RemoveHandler (SelectedNodeChangedEvent, value); }
207 public event TreeNodeEventHandler TreeNodeCollapsed {
208 add { Events.AddHandler (TreeNodeCollapsedEvent, value); }
209 remove { Events.RemoveHandler (TreeNodeCollapsedEvent, value); }
212 public event TreeNodeEventHandler TreeNodeDataBound {
213 add { Events.AddHandler (TreeNodeDataBoundEvent, value); }
214 remove { Events.RemoveHandler (TreeNodeDataBoundEvent, value); }
217 public event TreeNodeEventHandler TreeNodeExpanded {
218 add { Events.AddHandler (TreeNodeExpandedEvent, value); }
219 remove { Events.RemoveHandler (TreeNodeExpandedEvent, value); }
222 public event TreeNodeEventHandler TreeNodePopulate {
223 add { Events.AddHandler (TreeNodePopulateEvent, value); }
224 remove { Events.RemoveHandler (TreeNodePopulateEvent, value); }
227 protected virtual void OnTreeNodeCheckChanged (TreeNodeEventArgs e)
229 if (Events != null) {
230 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCheckChangedEvent];
231 if (eh != null) eh (this, e);
235 protected virtual void OnSelectedNodeChanged (EventArgs e)
237 if (Events != null) {
238 EventHandler eh = (EventHandler) Events [SelectedNodeChangedEvent];
239 if (eh != null) eh (this, e);
243 protected virtual void OnTreeNodeCollapsed (TreeNodeEventArgs e)
245 if (Events != null) {
246 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCollapsedEvent];
247 if (eh != null) eh (this, e);
251 protected virtual void OnTreeNodeDataBound (TreeNodeEventArgs e)
253 if (Events != null) {
254 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeDataBoundEvent];
255 if (eh != null) eh (this, e);
259 protected virtual void OnTreeNodeExpanded (TreeNodeEventArgs e)
261 if (Events != null) {
262 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeExpandedEvent];
263 if (eh != null) eh (this, e);
267 protected virtual void OnTreeNodePopulate (TreeNodeEventArgs e)
269 if (Events != null) {
270 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodePopulateEvent];
271 if (eh != null) eh (this, e);
277 public string CollapseImageToolTip {
279 return ViewState.GetString ("CollapseImageToolTip", "Collapse {0}");
282 ViewState["CollapseImageToolTip"] = value;
286 [MonoTODO ("Implement support for this")]
287 [WebCategory ("Behavior")]
288 [WebSysDescription ("Whether the tree will automatically generate bindings.")]
289 [DefaultValue (true)]
290 public bool AutoGenerateDataBindings {
292 return ViewState.GetBool ("AutoGenerateDataBindings", true);
295 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 {
306 return ViewState.GetString ("CollapseImageUrl", "");
309 ViewState["CollapseImageUrl"] = value;
313 [WebCategory ("Data")]
314 [PersistenceMode (PersistenceMode.InnerProperty)]
315 [WebSysDescription ("Bindings for tree nodes.")]
316 [Editor ("System.Web.UI.Design.WebControls.TreeViewBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
317 [DefaultValue (null)]
318 [MergablePropertyAttribute (false)]
319 public TreeNodeBindingCollection DataBindings {
321 if (dataBindings == null) {
322 dataBindings = new TreeNodeBindingCollection ();
323 if (IsTrackingViewState)
324 ((IStateManager)dataBindings).TrackViewState();
330 [WebCategory ("Behavior")]
331 [WebSysDescription ("Whether the tree view can use client-side script to expand and collapse nodes.")]
333 [DefaultValue (true)]
334 public bool EnableClientScript {
336 return ViewState.GetBool ("EnableClientScript", true);
339 ViewState["EnableClientScript"] = value;
344 [WebCategory ("Behavior")]
345 [WebSysDescription ("The initial expand depth.")]
346 [TypeConverter ("System.Web.UI.WebControls.TreeView+TreeViewExpandDepthConverter, " + Consts.AssemblySystem_Web)]
347 public int ExpandDepth {
349 return ViewState.GetInt ("ExpandDepth", -1);
352 ViewState["ExpandDepth"] = value;
357 public string ExpandImageToolTip {
359 return ViewState.GetString ("ExpandImageToolTip", "Expand {0}");
362 ViewState["ExpandImageToolTip"] = value;
368 [WebSysDescription ("The url of the image to show when a node can be expanded.")]
369 [WebCategory ("Appearance")]
370 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
371 public string ExpandImageUrl {
373 return ViewState.GetString ("ExpandImageUrl", "");
376 ViewState["ExpandImageUrl"] = value;
380 [PersistenceMode (PersistenceMode.InnerProperty)]
381 [NotifyParentProperty (true)]
382 [DefaultValue (null)]
383 [WebCategory ("Styles")]
384 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
385 public Style HoverNodeStyle {
387 if (hoverNodeStyle == null) {
388 hoverNodeStyle = new Style();
389 if (IsTrackingViewState)
390 hoverNodeStyle.TrackViewState();
392 return hoverNodeStyle;
396 [DefaultValue (TreeViewImageSet.Custom)]
397 public TreeViewImageSet ImageSet {
399 return (TreeViewImageSet)ViewState.GetInt ("ImageSet", (int)TreeViewImageSet.Custom);
402 if (!Enum.IsDefined (typeof (TreeViewImageSet), value))
403 throw new ArgumentOutOfRangeException ();
404 ViewState["ImageSet"] = value;
408 [PersistenceMode (PersistenceMode.InnerProperty)]
409 [NotifyParentProperty (true)]
410 [DefaultValue (null)]
411 [WebCategory ("Styles")]
412 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
413 public TreeNodeStyle LeafNodeStyle {
415 if (leafNodeStyle == null) {
416 leafNodeStyle = new TreeNodeStyle ();
417 if (IsTrackingViewState)
418 leafNodeStyle.TrackViewState();
420 return leafNodeStyle;
424 [DefaultValue (null)]
425 [WebCategory ("Styles")]
426 [PersistenceMode (PersistenceMode.InnerProperty)]
427 [Editor ("System.Web.UI.Design.WebControls.TreeNodeStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
428 public TreeNodeStyleCollection LevelStyles {
430 if (levelStyles == null) {
431 levelStyles = new TreeNodeStyleCollection ();
432 if (IsTrackingViewState)
433 ((IStateManager)levelStyles).TrackViewState();
440 public string LineImagesFolder {
442 return ViewState.GetString ("LineImagesFolder", "");
445 ViewState["LineImagesFolder"] = value;
450 public int MaxDataBindDepth {
452 return ViewState.GetInt ("MaxDataBindDepth", -1);
455 ViewState["MaxDataBindDepth"] = value;
460 public int NodeIndent {
462 return ViewState.GetInt ("NodeIndent", 20);
465 ViewState["NodeIndent"] = value;
469 [PersistenceMode (PersistenceMode.InnerProperty)]
470 [Editor ("System.Web.UI.Design.WebControls.TreeNodeCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
471 [DefaultValueAttribute (null)]
472 [MergablePropertyAttribute (false)]
473 public TreeNodeCollection Nodes {
476 nodes = new TreeNodeCollection (this);
477 if (IsTrackingViewState)
478 ((IStateManager)nodes).TrackViewState();
484 [PersistenceMode (PersistenceMode.InnerProperty)]
485 [NotifyParentProperty (true)]
486 [DefaultValue (null)]
487 [WebCategory ("Styles")]
488 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
489 public TreeNodeStyle NodeStyle {
491 if (nodeStyle == null) {
492 nodeStyle = new TreeNodeStyle ();
493 if (IsTrackingViewState)
494 nodeStyle.TrackViewState();
500 [DefaultValue (false)]
501 public bool NodeWrap {
503 return ViewState.GetBool ("NodeWrap", false);
506 ViewState ["NodeWrap"] = value;
512 [WebSysDescription ("The url of the image to show for leaf nodes.")]
513 [WebCategory ("Appearance")]
514 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
515 public string NoExpandImageUrl {
517 return ViewState.GetString ("NoExpandImageUrl", "");
520 ViewState ["NoExpandImageUrl"] = value;
524 [PersistenceMode (PersistenceMode.InnerProperty)]
525 [NotifyParentProperty (true)]
526 [DefaultValue (null)]
527 [WebCategory ("Styles")]
528 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
529 public TreeNodeStyle ParentNodeStyle {
531 if (parentNodeStyle == null) {
532 parentNodeStyle = new TreeNodeStyle ();
533 if (IsTrackingViewState)
534 parentNodeStyle.TrackViewState();
536 return parentNodeStyle;
541 public char PathSeparator {
543 return ViewState.GetChar ("PathSeparator", '/');
546 ViewState ["PathSeparator"] = value;
550 [DefaultValue (true)]
551 public bool PopulateNodesFromClient {
553 return ViewState.GetBool ("PopulateNodesFromClient", true);
556 ViewState ["PopulateNodesFromClient"] = value;
560 [PersistenceMode (PersistenceMode.InnerProperty)]
561 [NotifyParentProperty (true)]
562 [DefaultValue (null)]
563 [WebCategory ("Styles")]
564 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
565 public TreeNodeStyle RootNodeStyle {
567 if (rootNodeStyle == null) {
568 rootNodeStyle = new TreeNodeStyle ();
569 if (IsTrackingViewState)
570 rootNodeStyle.TrackViewState();
572 return rootNodeStyle;
576 [PersistenceMode (PersistenceMode.InnerProperty)]
577 [NotifyParentProperty (true)]
578 [DefaultValue (null)]
579 [WebCategory ("Styles")]
580 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
581 public TreeNodeStyle SelectedNodeStyle {
583 if (selectedNodeStyle == null) {
584 selectedNodeStyle = new TreeNodeStyle ();
585 if (IsTrackingViewState)
586 selectedNodeStyle.TrackViewState();
588 return selectedNodeStyle;
592 Style ControlLinkStyle {
594 if (controlLinkStyle == null) {
595 controlLinkStyle = new Style ();
596 controlLinkStyle.AlwaysRenderTextDecoration = true;
598 return controlLinkStyle;
602 Style NodeLinkStyle {
604 if (nodeLinkStyle == null) {
605 nodeLinkStyle = new Style ();
607 return nodeLinkStyle;
611 Style RootNodeLinkStyle {
613 if (rootNodeLinkStyle == null) {
614 rootNodeLinkStyle = new Style ();
616 return rootNodeLinkStyle;
620 Style ParentNodeLinkStyle {
622 if (parentNodeLinkStyle == null) {
623 parentNodeLinkStyle = new Style ();
625 return parentNodeLinkStyle;
629 Style SelectedNodeLinkStyle {
631 if (selectedNodeLinkStyle == null) {
632 selectedNodeLinkStyle = new Style ();
634 return selectedNodeLinkStyle;
638 Style LeafNodeLinkStyle {
640 if (leafNodeLinkStyle == null) {
641 leafNodeLinkStyle = new Style ();
643 return leafNodeLinkStyle;
647 Style HoverNodeLinkStyle {
649 if (hoverNodeLinkStyle == null) {
650 hoverNodeLinkStyle = new Style ();
652 return hoverNodeLinkStyle;
656 [DefaultValue (TreeNodeTypes.None)]
657 public TreeNodeTypes ShowCheckBoxes {
659 return (TreeNodeTypes)ViewState.GetInt ("ShowCheckBoxes", (int)TreeNodeTypes.None);
663 throw new ArgumentOutOfRangeException ();
664 ViewState ["ShowCheckBoxes"] = value;
668 [DefaultValue (true)]
669 public bool ShowExpandCollapse {
671 return ViewState.GetBool ("ShowExpandCollapse", true);
674 ViewState ["ShowExpandCollapse"] = value;
678 [DefaultValue (false)]
679 public bool ShowLines {
681 return ViewState.GetBool ("ShowLines", false);
684 ViewState ["ShowLines"] = value;
689 public string SkipLinkText
692 return ViewState.GetString ("SkipLinkText", "Skip Navigation Links.");
695 ViewState ["SkipLinkText"] = value;
701 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
702 public TreeNode SelectedNode {
703 get { return selectedNode; }
708 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
709 public string SelectedValue {
710 get { return selectedNode != null ? selectedNode.Value : ""; }
714 public string Target {
716 return ViewState.GetString ("Target", "");
719 ViewState ["Target"] = value;
723 [MonoTODO ("why override?")]
724 public override bool Visible
730 base.Visible = value;
735 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
736 public TreeNodeCollection CheckedNodes {
738 TreeNodeCollection col = new TreeNodeCollection ();
739 FindCheckedNodes (Nodes, col);
744 void FindCheckedNodes (TreeNodeCollection nodeList, TreeNodeCollection result)
746 foreach (TreeNode node in nodeList) {
747 if (node.Checked) result.Add (node, false);
748 FindCheckedNodes (node.ChildNodes, result);
752 public void ExpandAll ()
754 foreach (TreeNode node in Nodes)
758 public void CollapseAll ()
760 foreach (TreeNode node in Nodes)
764 public TreeNode FindNode (string valuePath)
766 if (valuePath == null) throw new ArgumentNullException ("valuePath");
767 string[] path = valuePath.Split (PathSeparator);
769 TreeNodeCollection col = Nodes;
770 bool foundBranch = true;
771 while (col.Count > 0 && foundBranch) {
773 foreach (TreeNode node in col) {
774 if (node.Value == path [n]) {
775 if (++n == path.Length) return node;
776 col = node.ChildNodes;
785 ImageStyle GetImageStyle ()
787 if (ImageSet != TreeViewImageSet.Custom)
788 return (ImageStyle) imageStyles [ImageSet];
793 protected override HtmlTextWriterTag TagKey {
794 get { return HtmlTextWriterTag.Div; }
797 protected internal virtual TreeNode CreateNode ()
799 return new TreeNode (this);
802 public sealed override void DataBind ()
807 protected void SetNodeDataBound (TreeNode node, bool dataBound)
809 node.SetDataBound (dataBound);
812 protected void SetNodeDataPath (TreeNode node, string dataPath)
814 node.SetDataPath (dataPath);
817 protected void SetNodeDataItem (TreeNode node, object dataItem)
819 node.SetDataItem (dataItem);
822 protected internal override void OnInit (EventArgs e)
827 internal void SetSelectedNode (TreeNode node, bool loading)
829 if (selectedNode == node) return;
830 if (selectedNode != null)
831 selectedNode.SelectedFlag = false;
834 OnSelectedNodeChanged (new TreeNodeEventArgs (selectedNode));
837 internal void NotifyCheckChanged (TreeNode node)
839 OnTreeNodeCheckChanged (new TreeNodeEventArgs (node));
842 internal void NotifyExpandedChanged (TreeNode node)
844 if (node.Expanded.HasValue && node.Expanded.Value)
845 OnTreeNodeExpanded (new TreeNodeEventArgs (node));
846 else if (node.Expanded.HasValue && node.IsParentNode)
847 OnTreeNodeCollapsed (new TreeNodeEventArgs (node));
850 internal void NotifyPopulateRequired (TreeNode node)
852 OnTreeNodePopulate (new TreeNodeEventArgs (node));
855 protected override void TrackViewState()
859 base.TrackViewState();
860 if (hoverNodeStyle != null) {
861 hoverNodeStyle.TrackViewState();
863 if (leafNodeStyle != null) {
864 leafNodeStyle.TrackViewState();
866 if (levelStyles != null && levelStyles.Count > 0) {
867 ((IStateManager)levelStyles).TrackViewState();
869 if (nodeStyle != null) {
870 nodeStyle.TrackViewState();
872 if (parentNodeStyle != null) {
873 parentNodeStyle.TrackViewState();
875 if (rootNodeStyle != null) {
876 rootNodeStyle.TrackViewState();
878 if (selectedNodeStyle != null) {
879 selectedNodeStyle.TrackViewState();
881 if (dataBindings != null) {
882 ((IStateManager)dataBindings).TrackViewState ();
885 ((IStateManager)nodes).TrackViewState();;
889 protected override object SaveViewState()
891 object[] states = new object [10];
892 states[0] = base.SaveViewState();
893 states[1] = (hoverNodeStyle == null ? null : hoverNodeStyle.SaveViewState());
894 states[2] = (leafNodeStyle == null ? null : leafNodeStyle.SaveViewState());
895 states[3] = (levelStyles == null ? null : ((IStateManager)levelStyles).SaveViewState());
896 states[4] = (nodeStyle == null ? null : nodeStyle.SaveViewState());
897 states[5] = (parentNodeStyle == null ? null : parentNodeStyle.SaveViewState());
898 states[6] = (rootNodeStyle == null ? null : rootNodeStyle.SaveViewState());
899 states[7] = (selectedNodeStyle == null ? null : selectedNodeStyle.SaveViewState());
900 states[8] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
901 states[9] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
903 for (int i = states.Length - 1; i >= 0; i--) {
904 if (states [i] != null)
911 protected override void LoadViewState (object savedState)
913 if (savedState == null)
916 object [] states = (object []) savedState;
917 base.LoadViewState (states[0]);
919 if (states[1] != null)
920 HoverNodeStyle.LoadViewState (states[1]);
921 if (states[2] != null)
922 LeafNodeStyle.LoadViewState(states[2]);
923 if (states[3] != null)
924 ((IStateManager)LevelStyles).LoadViewState(states[3]);
925 if (states[4] != null)
926 NodeStyle.LoadViewState(states[4]);
927 if (states[5] != null)
928 ParentNodeStyle.LoadViewState(states[5]);
929 if (states[6] != null)
930 RootNodeStyle.LoadViewState(states[6]);
931 if (states[7] != null)
932 SelectedNodeStyle.LoadViewState(states[7]);
933 if (states[8] != null)
934 ((IStateManager)DataBindings).LoadViewState(states[8]);
935 if (states[9] != null)
936 ((IStateManager)Nodes).LoadViewState(states[9]);
939 protected virtual void RaisePostBackEvent (string eventArgument)
941 ValidateEvent (UniqueID, eventArgument);
942 string[] args = eventArgument.Split ('|');
943 TreeNode node = FindNodeByPos (args[1]);
944 if (node == null) return;
946 if (args [0] == "sel")
947 HandleSelectEvent (node);
948 else if (args [0] == "ec")
949 HandleExpandCollapseEvent (node);
952 void HandleSelectEvent (TreeNode node)
954 switch (node.SelectAction) {
955 case TreeNodeSelectAction.Select:
958 case TreeNodeSelectAction.Expand:
961 case TreeNodeSelectAction.SelectExpand:
968 void HandleExpandCollapseEvent (TreeNode node)
970 node.ToggleExpandState ();
973 protected virtual void RaisePostDataChangedEvent ()
977 string callbackResult;
978 protected virtual void RaiseCallbackEvent (string eventArgs)
980 RequiresDataBinding = true;
983 TreeNode node = FindNodeByPos (eventArgs);
984 ArrayList levelLines = new ArrayList ();
987 int childCount = nd.Parent != null ? nd.Parent.ChildNodes.Count : Nodes.Count;
988 levelLines.Insert (0, (nd.Index < childCount - 1) ? this : null);
992 StringWriter sw = new StringWriter ();
993 HtmlTextWriter writer = new HtmlTextWriter (sw);
994 EnsureStylesPrepared ();
996 node.Expanded = true;
997 int num = node.ChildNodes.Count;
998 for (int n=0; n<num; n++)
999 RenderNode (writer, node.ChildNodes [n], node.Depth + 1, levelLines, true, n<num-1);
1001 string res = sw.ToString ();
1002 callbackResult = res != "" ? res : "*";
1005 protected virtual string GetCallbackResult ()
1007 return callbackResult;
1010 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
1012 RaisePostBackEvent (eventArgument);
1015 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
1017 return LoadPostData (postDataKey, postCollection);
1020 void IPostBackDataHandler.RaisePostDataChangedEvent ()
1022 RaisePostDataChangedEvent ();
1025 void ICallbackEventHandler.RaiseCallbackEvent (string eventArgs)
1027 RaiseCallbackEvent (eventArgs);
1030 string ICallbackEventHandler.GetCallbackResult ()
1032 return GetCallbackResult ();
1035 protected override ControlCollection CreateControlCollection ()
1037 return new EmptyControlCollection (this);
1040 protected internal override void PerformDataBinding ()
1042 base.PerformDataBinding ();
1043 InitializeDataBindings ();
1044 HierarchicalDataSourceView data = GetData ("");
1048 IHierarchicalEnumerable e = data.Select ();
1049 FillBoundChildrenRecursive (e, Nodes);
1052 void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, TreeNodeCollection nodeCollection)
1054 if (hEnumerable == null)
1057 foreach (object obj in hEnumerable) {
1058 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
1059 TreeNode child = new TreeNode ();
1060 nodeCollection.Add (child);
1062 OnTreeNodeDataBound (new TreeNodeEventArgs (child));
1064 if (MaxDataBindDepth >= 0 && child.Depth == MaxDataBindDepth)
1067 if (hdata == null || !hdata.HasChildren)
1070 IHierarchicalEnumerable e = hdata.GetChildren ();
1071 FillBoundChildrenRecursive (e, child.ChildNodes);
1075 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
1079 if (EnableClientScript && PopulateNodesFromClient) {
1080 string states = postCollection [ClientID + "_PopulatedStates"];
1081 if (states != null) {
1082 foreach (string id in states.Split ('|')) {
1083 if (String.IsNullOrEmpty(id))
1085 TreeNode node = FindNodeByPos (id);
1086 if (node != null && node.PopulateOnDemand && !node.Populated)
1093 UnsetCheckStates (Nodes, postCollection);
1094 SetCheckStates (postCollection);
1096 if (EnableClientScript) {
1097 string states = postCollection [ClientID + "_ExpandStates"];
1098 if (states != null) {
1099 string[] ids = states.Split ('|');
1100 UnsetExpandStates (Nodes, ids);
1101 SetExpandStates (ids);
1104 UnsetExpandStates (Nodes, new string[0]);
1110 protected internal override void OnPreRender (EventArgs e)
1112 base.OnPreRender (e);
1116 Page.RegisterRequiresPostBack (this);
1118 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1119 string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1120 Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1124 string ctree = ClientID + "_data";
1125 string script = string.Format ("var {0} = new Object ();\n", ctree);
1126 script += string.Format ("{0}.treeId = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (ClientID));
1127 script += string.Format ("{0}.uid = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (UniqueID));
1128 script += string.Format ("{0}.showImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));
1130 if (ShowExpandCollapse) {
1131 ImageStyle imageStyle = GetImageStyle ();
1132 script += string.Format ("{0}.expandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)));
1133 script += string.Format ("{0}.collapseImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)));
1134 if (PopulateNodesFromClient)
1135 script += string.Format ("{0}.noExpandImage = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)));
1139 script += string.Format ("{0}.form = {1};\n", ctree, Page.theForm);
1140 script += string.Format (
1141 @"{0}.PopulateNode = function(nodeId) {{
1142 " + Page.WebFormScriptReference + @".__theFormPostData = """";
1143 " + Page.WebFormScriptReference + @".__theFormPostCollection = new Array();
1144 " + Page.WebFormScriptReference + @".WebForm_InitCallback();
1147 ", ctree, Page.ClientScript.GetCallbackEventReference ("this.uid", "nodeId", "TreeView_PopulateCallback", "this.treeId + \" \" + nodeId", "TreeView_PopulateCallback", false));
1148 script += string.Format ("{0}.populateFromClient = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient));
1149 script += string.Format ("{0}.expandAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)));
1150 script += string.Format ("{0}.collapseAlt = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1152 if (!Page.IsPostBack) {
1153 SetNodesExpandedToDepthRecursive (Nodes);
1156 if (EnableClientScript) {
1157 Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1159 // Make sure the basic script infrastructure is rendered
1160 Page.ClientScript.RegisterWebFormClientScript ();
1163 if (EnableClientScript && PopulateNodesFromClient) {
1164 Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1167 EnsureStylesPrepared ();
1169 if (hoverNodeStyle != null) {
1170 if (Page.Header == null)
1171 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1172 RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1173 script += string.Format ("{0}.hoverClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass));
1174 script += string.Format ("{0}.hoverLinkClass = {1};\n", ctree, ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass));
1177 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
1181 void EnsureStylesPrepared () {
1184 stylesPrepared = true;
1188 void PrepareStyles () {
1189 // The order in which styles are defined matters when more than one class
1190 // is assigned to an element
1191 ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1192 RegisterStyle (ControlLinkStyle);
1194 if (nodeStyle != null)
1195 RegisterStyle (NodeStyle, NodeLinkStyle);
1197 if (rootNodeStyle != null)
1198 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1200 if (parentNodeStyle != null)
1201 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1203 if (leafNodeStyle != null)
1204 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1207 if (levelStyles != null && levelStyles.Count > 0) {
1208 levelLinkStyles = new List<Style> (levelStyles.Count);
1209 foreach (Style style in levelStyles) {
1210 Style linkStyle = new Style ();
1211 levelLinkStyles.Add (linkStyle);
1212 RegisterStyle (style, linkStyle);
1216 if (selectedNodeStyle != null)
1217 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1220 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes) {
1221 foreach (TreeNode node in nodes) {
1222 if (!node.Expanded.HasValue) {
1223 if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1224 node.Expanded = true;
1226 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1230 string IncrementStyleClassName () {
1231 registeredStylesCounter++;
1232 return ClientID + "_" + registeredStylesCounter;
1235 void RegisterStyle (Style baseStyle, Style linkStyle) {
1236 linkStyle.CopyTextStylesFrom (baseStyle);
1237 linkStyle.BorderStyle = BorderStyle.None;
1238 baseStyle.Font.Reset ();
1239 RegisterStyle (linkStyle);
1240 RegisterStyle (baseStyle);
1243 void RegisterStyle (Style baseStyle) {
1244 if (Page.Header == null)
1246 string className = IncrementStyleClassName ().Trim ('_');
1247 baseStyle.SetRegisteredCssClass (className);
1248 Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1251 string GetBindingKey (string dataMember, int depth)
1253 return dataMember + " " + depth;
1256 void InitializeDataBindings () {
1257 if (dataBindings != null && dataBindings.Count > 0) {
1258 bindings = new Hashtable ();
1259 foreach (TreeNodeBinding bin in dataBindings) {
1260 string key = GetBindingKey (bin.DataMember, bin.Depth);
1261 if (!bindings.ContainsKey(key))
1262 bindings [key] = bin;
1269 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1271 if (bindings == null)
1274 TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1275 if (bin != null) return bin;
1277 bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1278 if (bin != null) return bin;
1280 bin = (TreeNodeBinding) bindings [GetBindingKey ("", depth)];
1281 if (bin != null) return bin;
1283 return (TreeNodeBinding) bindings [GetBindingKey ("", -1)];
1286 internal void DecorateNode(TreeNode node)
1291 if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1294 if (node.IsRootNode && rootNodeStyle != null) {
1295 node.ImageUrl = rootNodeStyle.ImageUrl;
1298 if (node.IsParentNode && parentNodeStyle != null) {
1299 node.ImageUrl = parentNodeStyle.ImageUrl;
1302 if (node.IsLeafNode && leafNodeStyle != null)
1303 node.ImageUrl = leafNodeStyle.ImageUrl;
1306 protected internal override void RenderContents (HtmlTextWriter writer)
1308 SiteMapDataSource siteMap = GetDataSource () as SiteMapDataSource;
1309 bool checkSitePath = IsBoundUsingDataSourceID && siteMap != null;
1311 if (checkSitePath) {
1312 IHierarchyData data = siteMap.Provider.CurrentNode;
1314 activeSiteMapPath = data.Path;
1317 ArrayList levelLines = new ArrayList ();
1318 int num = Nodes.Count;
1319 for (int n=0; n<num; n++)
1320 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1323 protected override void AddAttributesToRender(HtmlTextWriter writer)
1325 base.AddAttributesToRender (writer);
1328 public override void RenderBeginTag (HtmlTextWriter writer)
1330 if (SkipLinkText != "") {
1331 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1332 writer.RenderBeginTag (HtmlTextWriterTag.A);
1334 Image img = new Image ();
1335 ClientScriptManager csm = new ClientScriptManager (null);
1336 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1337 img.Attributes.Add ("height", "0");
1338 img.Attributes.Add ("width", "0");
1339 img.AlternateText = SkipLinkText;
1340 img.Render (writer);
1342 writer.RenderEndTag ();
1344 base.RenderBeginTag (writer);
1347 public override void RenderEndTag (HtmlTextWriter writer)
1349 base.RenderEndTag (writer);
1351 if (SkipLinkText != "") {
1352 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1353 writer.RenderBeginTag (HtmlTextWriterTag.A);
1354 writer.RenderEndTag ();
1358 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1363 bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1364 ImageStyle imageStyle = GetImageStyle ();
1365 bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1367 if (clientExpand && !renderChildNodes)
1368 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1372 if (renderChildNodes)
1373 hasChildNodes = node.ChildNodes.Count > 0;
1375 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1377 writer.AddAttribute ("cellpadding", "0", false);
1378 writer.AddAttribute ("cellspacing", "0", false);
1379 writer.AddStyleAttribute ("border-width", "0");
1380 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1382 Unit nodeSpacing = GetNodeSpacing (node);
1384 if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1385 RenderMenuItemSpacing (writer, nodeSpacing);
1387 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1389 // Vertical lines from previous levels
1391 nodeImage = GetNodeImageUrl ("i", imageStyle);
1392 for (int n=0; n<level; n++) {
1393 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1394 writer.AddStyleAttribute ("width", NodeIndent + "px");
1395 writer.AddStyleAttribute ("height", "1px");
1396 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1397 if (ShowLines && levelLines [n] != null) {
1398 writer.AddAttribute ("src", nodeImage);
1399 writer.AddAttribute (HtmlTextWriterAttribute.Alt, "", false);
1400 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1401 writer.RenderEndTag ();
1403 writer.RenderEndTag ();
1404 writer.RenderEndTag (); // TD
1407 // Node image + line
1409 if (ShowExpandCollapse || ShowLines) {
1410 bool buttonImage = false;
1411 string tooltip = "";
1415 if (hasPrevious && hasNext) shape = "t";
1416 else if (hasPrevious && !hasNext) shape = "l";
1417 else if (!hasPrevious && hasNext) shape = "r";
1418 else shape = "dash";
1421 if (ShowExpandCollapse) {
1422 if (hasChildNodes) {
1424 if (node.Expanded.HasValue && node.Expanded.Value) shape += "minus";
1425 else shape += "plus";
1426 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1427 } else if (!ShowLines)
1432 nodeImage = GetNodeImageUrl (shape, imageStyle);
1433 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1436 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1437 writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1439 writer.AddAttribute ("href", GetClientExpandEvent(node));
1440 writer.RenderBeginTag (HtmlTextWriterTag.A); // Anchor
1443 writer.AddAttribute ("alt", tooltip);
1445 if (buttonImage && clientExpand)
1446 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1447 writer.AddAttribute ("src", nodeImage);
1449 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1450 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1451 writer.RenderEndTag ();
1454 writer.RenderEndTag (); // Anchor
1456 writer.RenderEndTag (); // TD
1462 string imageUrl = node.ImageUrl.Length > 0 ? ResolveClientUrl (node.ImageUrl) : null;
1463 if (String.IsNullOrEmpty (imageUrl) && imageStyle != null) {
1464 if (imageStyle.RootIcon != null && node.IsRootNode)
1465 imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1466 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1467 imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1468 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1469 imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1472 if (level < LevelStyles.Count && LevelStyles [level].ImageUrl != null)
1473 imageUrl = ResolveClientUrl (LevelStyles [level].ImageUrl);
1475 if (!String.IsNullOrEmpty (imageUrl)) {
1476 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1477 BeginNodeTag (writer, node, clientExpand);
1478 writer.AddAttribute ("src", imageUrl);
1479 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1480 writer.AddAttribute ("alt", node.ImageToolTip);
1481 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1482 writer.RenderEndTag (); // IMG
1483 writer.RenderEndTag (); // style tag
1484 writer.RenderEndTag (); // TD
1488 writer.AddStyleAttribute ("white-space", "nowrap");
1490 bool nodeIsSelected = node == SelectedNode && selectedNodeStyle != null;
1491 if (!nodeIsSelected && selectedNodeStyle != null) {
1492 if (!String.IsNullOrEmpty (activeSiteMapPath))
1493 nodeIsSelected = String.Compare (activeSiteMapPath,
1495 HttpRuntime.CaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == 0;
1498 AddNodeStyle (writer, node, level, nodeIsSelected);
1499 if (EnableClientScript) {
1500 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)", false);
1501 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1503 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1507 if (node.ShowCheckBoxInternal) {
1508 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1509 writer.AddAttribute ("type", "checkbox", false);
1510 writer.AddAttribute ("title", node.Text);
1511 if (node.Checked) writer.AddAttribute ("checked", "checked", false);
1512 writer.RenderBeginTag (HtmlTextWriterTag.Input); // INPUT
1513 writer.RenderEndTag (); // INPUT
1518 node.BeginRenderText (writer);
1521 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1522 AddNodeLinkStyle (writer, node, level, nodeIsSelected);
1523 BeginNodeTag (writer, node, clientExpand);
1524 writer.Write (node.Text);
1525 writer.RenderEndTag (); // style tag
1527 node.EndRenderText (writer);
1529 writer.RenderEndTag (); // TD
1531 writer.RenderEndTag (); // TR
1533 if (nodeSpacing != Unit.Empty)
1534 RenderMenuItemSpacing (writer, nodeSpacing);
1536 writer.RenderEndTag (); // TABLE
1540 if (hasChildNodes) {
1541 if (level >= levelLines.Count) {
1543 levelLines.Add (this);
1545 levelLines.Add (null);
1548 levelLines [level] = this;
1550 levelLines [level] = null;
1554 if (!(node.Expanded.HasValue && node.Expanded.Value))
1555 writer.AddStyleAttribute ("display", "none");
1557 writer.AddStyleAttribute ("display", "block");
1558 writer.AddAttribute ("id", GetNodeClientId (node, null));
1559 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1561 if (renderChildNodes) {
1562 AddChildrenPadding (writer, node);
1563 int num = node.ChildNodes.Count;
1564 for (int n=0; n<num; n++)
1565 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1567 AddChildrenPadding (writer, node);
1569 writer.RenderEndTag (); // SPAN
1570 } else 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);
1581 void AddChildrenPadding (HtmlTextWriter writer, TreeNode node)
1583 int level = node.Depth;
1584 Unit cnp = Unit.Empty;
1586 if (levelStyles != null && level < levelStyles.Count)
1587 cnp = levelStyles [level].ChildNodesPadding;
1588 if (cnp.IsEmpty && nodeStyle != null)
1589 cnp = nodeStyle.ChildNodesPadding;
1592 if (cnp.IsEmpty || (value = cnp.Value) == 0 || cnp.Type != UnitType.Pixel)
1595 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1596 writer.AddAttribute ("height", ((int) value).ToString (), false);
1597 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1598 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1599 writer.RenderEndTag (); // td
1600 writer.RenderEndTag (); // tr
1601 writer.RenderEndTag (); // table
1604 void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing) {
1605 writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1606 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1607 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1608 writer.RenderEndTag ();
1609 writer.RenderEndTag ();
1612 Unit GetNodeSpacing (TreeNode node) {
1613 if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty) {
1614 return selectedNodeStyle.NodeSpacing;
1617 if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty) {
1618 return levelStyles [node.Depth].NodeSpacing;
1621 if (node.IsLeafNode) {
1622 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1623 return leafNodeStyle.NodeSpacing;
1625 else if (node.IsRootNode) {
1626 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1627 return rootNodeStyle.NodeSpacing;
1629 else if (node.IsParentNode) {
1630 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1631 return parentNodeStyle.NodeSpacing;
1634 if (nodeStyle != null)
1635 return nodeStyle.NodeSpacing;
1640 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1642 TreeNodeStyle style = new TreeNodeStyle ();
1643 if (Page.Header != null) {
1644 // styles are registered
1645 if (nodeStyle != null) {
1646 style.AddCssClass (nodeStyle.CssClass);
1647 style.AddCssClass (nodeStyle.RegisteredCssClass);
1649 if (node.IsLeafNode) {
1650 if (leafNodeStyle != null) {
1651 style.AddCssClass (leafNodeStyle.CssClass);
1652 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1654 } else if (node.IsRootNode) {
1655 if (rootNodeStyle != null) {
1656 style.AddCssClass (rootNodeStyle.CssClass);
1657 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1659 } else if (node.IsParentNode) {
1660 if (parentNodeStyle != null) {
1661 style.AddCssClass (parentNodeStyle.CssClass);
1662 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1665 if (levelStyles != null && levelStyles.Count > level) {
1666 style.AddCssClass (levelStyles [level].CssClass);
1667 style.AddCssClass (levelStyles [level].RegisteredCssClass);
1670 if (nodeIsSelected) {
1671 style.AddCssClass (selectedNodeStyle.CssClass);
1672 style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1675 // styles are not registered
1676 if (nodeStyle != null) {
1677 style.CopyFrom (nodeStyle);
1679 if (node.IsLeafNode) {
1680 if (leafNodeStyle != null) {
1681 style.CopyFrom (leafNodeStyle);
1684 else if (node.IsRootNode) {
1685 if (rootNodeStyle != null) {
1686 style.CopyFrom (rootNodeStyle);
1689 else if (node.IsParentNode) {
1690 if (parentNodeStyle != null) {
1691 style.CopyFrom (parentNodeStyle);
1694 if (levelStyles != null && levelStyles.Count > level) {
1695 style.CopyFrom (levelStyles [level]);
1698 if (nodeIsSelected) {
1699 style.CopyFrom (selectedNodeStyle);
1702 style.AddAttributesToRender (writer);
1705 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level, bool nodeIsSelected)
1707 Style style = new Style ();
1708 if (Page.Header != null) {
1709 // styles are registered
1710 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1712 if (nodeStyle != null) {
1713 style.AddCssClass (nodeLinkStyle.CssClass);
1714 style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1716 if (node.IsLeafNode) {
1717 if (leafNodeStyle != null) {
1718 style.AddCssClass (leafNodeLinkStyle.CssClass);
1719 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1722 else if (node.IsRootNode) {
1723 if (rootNodeStyle != null) {
1724 style.AddCssClass (rootNodeLinkStyle.CssClass);
1725 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1728 else if (node.IsParentNode) {
1729 if (parentNodeStyle != null) {
1730 style.AddCssClass (parentNodeLinkStyle.CssClass);
1731 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1734 if (levelStyles != null && levelStyles.Count > level) {
1735 style.AddCssClass (levelLinkStyles [level].CssClass);
1736 style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1738 if (nodeIsSelected) {
1739 style.AddCssClass (selectedNodeLinkStyle.CssClass);
1740 style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1744 // styles are not registered
1745 style.CopyFrom (ControlLinkStyle);
1746 if (nodeStyle != null) {
1747 style.CopyFrom (nodeLinkStyle);
1749 if (node.IsLeafNode) {
1750 if (node.IsLeafNode && leafNodeStyle != null) {
1751 style.CopyFrom (leafNodeLinkStyle);
1754 else if (node.IsRootNode) {
1755 if (node.IsRootNode && rootNodeStyle != null) {
1756 style.CopyFrom (rootNodeLinkStyle);
1759 else if (node.IsParentNode) {
1760 if (node.IsParentNode && parentNodeStyle != null) {
1761 style.CopyFrom (parentNodeLinkStyle);
1764 if (levelStyles != null && levelStyles.Count > level) {
1765 style.CopyFrom (levelLinkStyles [level]);
1767 if (nodeIsSelected) {
1768 style.CopyFrom (selectedNodeLinkStyle);
1770 style.AlwaysRenderTextDecoration = true;
1772 style.AddAttributesToRender (writer);
1775 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1777 if(node.ToolTip.Length>0)
1778 writer.AddAttribute ("title", node.ToolTip);
1780 if (node.NavigateUrl != "") {
1781 string target = node.Target.Length > 0 ? node.Target : Target;
1783 string navUrl = ResolveClientUrl (node.NavigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1785 string navUrl = ResolveClientUrl (node.NavigateUrl);
1787 writer.AddAttribute ("href", navUrl);
1788 if (target.Length > 0)
1789 writer.AddAttribute ("target", target);
1790 writer.RenderBeginTag (HtmlTextWriterTag.A);
1792 else if (node.SelectAction != TreeNodeSelectAction.None) {
1793 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1794 writer.AddAttribute ("href", GetClientExpandEvent (node));
1796 writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1797 writer.RenderBeginTag (HtmlTextWriterTag.A);
1800 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1803 string GetNodeImageToolTip (bool expand, string txt) {
1805 if (ExpandImageToolTip != "")
1806 return String.Format (ExpandImageToolTip, txt);
1807 else if (txt != null)
1808 return "Expand " + txt;
1810 return "Expand {0}";
1812 if (CollapseImageToolTip != "")
1813 return String.Format (CollapseImageToolTip, txt);
1814 else if (txt != null)
1815 return "Collapse " + txt;
1817 return "Collapse {0}";
1821 string GetNodeClientId (TreeNode node, string sufix)
1823 return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : "");
1826 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1829 if (!String.IsNullOrEmpty (LineImagesFolder))
1830 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1832 if (imageStyle != null) {
1833 if (shape == "plus") {
1834 if (!String.IsNullOrEmpty (imageStyle.Expand))
1835 return GetNodeIconUrl (imageStyle.Expand);
1837 else if (shape == "minus") {
1838 if (!String.IsNullOrEmpty (imageStyle.Collapse))
1839 return GetNodeIconUrl (imageStyle.Collapse);
1841 else if (shape == "noexpand") {
1842 if (!String.IsNullOrEmpty (imageStyle.NoExpand))
1843 return GetNodeIconUrl (imageStyle.NoExpand);
1847 if (shape == "plus") {
1848 if (!String.IsNullOrEmpty (ExpandImageUrl))
1849 return ResolveClientUrl (ExpandImageUrl);
1851 else if (shape == "minus") {
1852 if (!String.IsNullOrEmpty (CollapseImageUrl))
1853 return ResolveClientUrl (CollapseImageUrl);
1855 else if (shape == "noexpand") {
1856 if (!String.IsNullOrEmpty (NoExpandImageUrl))
1857 return ResolveClientUrl (NoExpandImageUrl);
1860 if (!String.IsNullOrEmpty (LineImagesFolder))
1861 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1863 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), "TreeView_" + shape + ".gif");
1866 string GetNodeIconUrl (string icon)
1868 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), icon + ".gif");
1871 string GetClientEvent (TreeNode node, string ev)
1873 return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path, true);
1876 string GetClientExpandEvent (TreeNode node)
1878 return "javascript:TreeView_ToggleExpand ('" + ClientID + "', '" + node.Path + "')";
1881 TreeNode FindNodeByPos (string path)
1883 string[] indexes = path.Split ('_');
1884 TreeNode node = null;
1886 foreach (string index in indexes) {
1887 int i = int.Parse (index);
1889 if (i >= Nodes.Count) return null;
1892 if (i >= node.ChildNodes.Count) return null;
1893 node = node.ChildNodes [i];
1899 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1901 foreach (TreeNode node in col) {
1902 if (node.ShowCheckBoxInternal && node.Checked) {
1903 if (states == null || states [ClientID + "_cs_" + node.Path] == null)
1904 node.Checked = false;
1906 if (node.HasChildData)
1907 UnsetCheckStates (node.ChildNodes, states);
1911 void SetCheckStates (NameValueCollection states)
1916 string keyPrefix = ClientID + "_cs_";
1917 foreach (string key in states) {
1918 if (key.StartsWith (keyPrefix, StringComparison.Ordinal)) {
1919 string id = key.Substring (keyPrefix.Length);
1920 TreeNode node = FindNodeByPos (id);
1921 if (node != null && !node.Checked)
1922 node.Checked = true;
1927 void UnsetExpandStates (TreeNodeCollection col, string[] states)
1929 foreach (TreeNode node in col) {
1930 if (node.Expanded.HasValue && node.Expanded.Value) {
1931 bool expand = (Array.IndexOf (states, node.Path) != -1);
1932 if (!expand) node.Expanded = false;
1934 if (node.HasChildData)
1935 UnsetExpandStates (node.ChildNodes, states);
1939 void SetExpandStates (string[] states)
1941 foreach (string id in states) {
1942 if (id == null || id == "") continue;
1943 TreeNode node = FindNodeByPos (id);
1945 node.Expanded = true;
1949 string GetExpandStates ()
1951 StringBuilder sb = new StringBuilder ("|");
1953 foreach (TreeNode node in Nodes)
1954 GetExpandStates (sb, node);
1956 return sb.ToString ();
1959 void GetExpandStates (StringBuilder sb, TreeNode node)
1961 if (node.Expanded.HasValue && node.Expanded.Value) {
1962 sb.Append (node.Path);
1965 if (node.HasChildData) {
1966 foreach (TreeNode child in node.ChildNodes)
1967 GetExpandStates (sb, child);