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