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.Web.Handlers;
37 using System.Collections.Specialized;
39 using System.Security.Permissions;
40 using System.Collections.Generic;
42 namespace System.Web.UI.WebControls
45 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
46 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48 [SupportsEventValidation]
49 [ControlValueProperty ("SelectedValue")]
50 [DefaultEvent ("SelectedNodeChanged")]
51 [Designer ("System.Web.UI.Design.WebControls.TreeViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
52 public class TreeView: HierarchicalDataBoundControl, IPostBackEventHandler, IPostBackDataHandler, ICallbackEventHandler
56 TreeNodeStyle leafNodeStyle;
57 TreeNodeStyle nodeStyle;
58 TreeNodeStyle parentNodeStyle;
59 TreeNodeStyle rootNodeStyle;
60 TreeNodeStyle selectedNodeStyle;
62 TreeNodeStyleCollection levelStyles;
63 TreeNodeCollection nodes;
64 TreeNodeBindingCollection dataBindings;
66 TreeNode selectedNode;
69 int registeredStylesCounter = -1;
70 List<Style> levelLinkStyles;
71 Style controlLinkStyle;
73 Style rootNodeLinkStyle;
74 Style parentNodeLinkStyle;
75 Style leafNodeLinkStyle;
76 Style selectedNodeLinkStyle;
77 Style hoverNodeLinkStyle;
79 private static readonly object TreeNodeCheckChangedEvent = new object();
80 private static readonly object SelectedNodeChangedEvent = new object();
81 private static readonly object TreeNodeCollapsedEvent = new object();
82 private static readonly object TreeNodeDataBoundEvent = new object();
83 private static readonly object TreeNodeExpandedEvent = new object();
84 private static readonly object TreeNodePopulateEvent = new object();
86 static Hashtable imageStyles = new Hashtable ();
90 public ImageStyle (string expand, string collapse, string noExpand, string icon, string iconLeaf, string iconRoot) {
100 public string Collapse;
101 public string NoExpand;
102 public string RootIcon;
103 public string ParentIcon;
104 public string LeafIcon;
109 imageStyles [TreeViewImageSet.Arrows] = new ImageStyle ("arrow_plus", "arrow_minus", "arrow_noexpand", null, null, null);
110 imageStyles [TreeViewImageSet.BulletedList] = new ImageStyle (null, null, null, "dot_full", "dot_empty", "dot_full");
111 imageStyles [TreeViewImageSet.BulletedList2] = new ImageStyle (null, null, null, "box_full", "box_empty", "box_full");
112 imageStyles [TreeViewImageSet.BulletedList3] = new ImageStyle (null, null, null, "star_full", "star_empty", "star_full");
113 imageStyles [TreeViewImageSet.BulletedList4] = new ImageStyle (null, null, null, "star_full", "star_empty", "dots");
114 imageStyles [TreeViewImageSet.Contacts] = new ImageStyle ("TreeView_plus", "TreeView_minus", "contact", null, null, null);
115 imageStyles [TreeViewImageSet.Events] = new ImageStyle (null, null, null, "warning", "warning", "warning");
116 imageStyles [TreeViewImageSet.Inbox] = new ImageStyle (null, null, null, "inbox", "inbox", "inbox");
117 imageStyles [TreeViewImageSet.Msdn] = new ImageStyle ("box_plus", "box_minus", "box_noexpand", null, null, null);
118 imageStyles [TreeViewImageSet.Simple] = new ImageStyle (null, null, "box_full", null, null, null);
119 imageStyles [TreeViewImageSet.Simple2] = new ImageStyle (null, null, "box_empty", null, null, null);
122 imageStyles [TreeViewImageSet.News] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
123 imageStyles [TreeViewImageSet.Faq] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
124 imageStyles [TreeViewImageSet.WindowsHelp] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
125 imageStyles [TreeViewImageSet.XPFileExplorer] = new ImageStyle ("TreeView_plus", "TreeView_minus", "TreeView_noexpand", null, null, null);
128 public event TreeNodeEventHandler TreeNodeCheckChanged {
129 add { Events.AddHandler (TreeNodeCheckChangedEvent, value); }
130 remove { Events.RemoveHandler (TreeNodeCheckChangedEvent, value); }
133 public event EventHandler SelectedNodeChanged {
134 add { Events.AddHandler (SelectedNodeChangedEvent, value); }
135 remove { Events.RemoveHandler (SelectedNodeChangedEvent, value); }
138 public event TreeNodeEventHandler TreeNodeCollapsed {
139 add { Events.AddHandler (TreeNodeCollapsedEvent, value); }
140 remove { Events.RemoveHandler (TreeNodeCollapsedEvent, value); }
143 public event TreeNodeEventHandler TreeNodeDataBound {
144 add { Events.AddHandler (TreeNodeDataBoundEvent, value); }
145 remove { Events.RemoveHandler (TreeNodeDataBoundEvent, value); }
148 public event TreeNodeEventHandler TreeNodeExpanded {
149 add { Events.AddHandler (TreeNodeExpandedEvent, value); }
150 remove { Events.RemoveHandler (TreeNodeExpandedEvent, value); }
153 public event TreeNodeEventHandler TreeNodePopulate {
154 add { Events.AddHandler (TreeNodePopulateEvent, value); }
155 remove { Events.RemoveHandler (TreeNodePopulateEvent, value); }
158 protected virtual void OnTreeNodeCheckChanged (TreeNodeEventArgs e)
160 if (Events != null) {
161 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCheckChangedEvent];
162 if (eh != null) eh (this, e);
166 protected virtual void OnSelectedNodeChanged (EventArgs e)
168 if (Events != null) {
169 EventHandler eh = (EventHandler) Events [SelectedNodeChangedEvent];
170 if (eh != null) eh (this, e);
174 protected virtual void OnTreeNodeCollapsed (TreeNodeEventArgs e)
176 if (Events != null) {
177 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeCollapsedEvent];
178 if (eh != null) eh (this, e);
182 protected virtual void OnTreeNodeDataBound (TreeNodeEventArgs e)
184 if (Events != null) {
185 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeDataBoundEvent];
186 if (eh != null) eh (this, e);
190 protected virtual void OnTreeNodeExpanded (TreeNodeEventArgs e)
192 if (Events != null) {
193 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodeExpandedEvent];
194 if (eh != null) eh (this, e);
198 protected virtual void OnTreeNodePopulate (TreeNodeEventArgs e)
200 if (Events != null) {
201 TreeNodeEventHandler eh = (TreeNodeEventHandler) Events [TreeNodePopulateEvent];
202 if (eh != null) eh (this, e);
208 public string CollapseImageToolTip {
210 return ViewState.GetString ("CollapseImageToolTip", "Collapse {0}");
213 ViewState["CollapseImageToolTip"] = value;
217 [MonoTODO ("Implement support for this")]
218 [WebCategory ("Behavior")]
219 [WebSysDescription ("Whether the tree will automatically generate bindings.")]
220 [DefaultValue (true)]
221 public bool AutoGenerateDataBindings {
223 return ViewState.GetBool ("AutoGenerateDataBindings", true);
226 ViewState["AutoGenerateDataBindings"] = value;
231 [WebSysDescription ("The url of the image to show when a node can be collapsed.")]
233 [WebCategory ("Appearance")]
234 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
235 public string CollapseImageUrl {
237 return ViewState.GetString ("CollapseImageUrl", "");
240 ViewState["CollapseImageUrl"] = value;
244 [WebCategory ("Data")]
245 [PersistenceMode (PersistenceMode.InnerProperty)]
246 [WebSysDescription ("Bindings for tree nodes.")]
247 [Editor ("System.Web.UI.Design.WebControls.TreeViewBindingsEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
248 [DefaultValue (null)]
249 [MergablePropertyAttribute (false)]
250 public TreeNodeBindingCollection DataBindings {
252 if (dataBindings == null) {
253 dataBindings = new TreeNodeBindingCollection ();
254 if (IsTrackingViewState)
255 ((IStateManager)dataBindings).TrackViewState();
261 [WebCategory ("Behavior")]
262 [WebSysDescription ("Whether the tree view can use client-side script to expand and collapse nodes.")]
264 [DefaultValue (true)]
265 public bool EnableClientScript {
267 return ViewState.GetBool ("EnableClientScript", true);
270 ViewState["EnableClientScript"] = value;
275 [WebCategory ("Behavior")]
276 [WebSysDescription ("The initial expand depth.")]
277 [TypeConverter ("System.Web.UI.WebControls.TreeView+TreeViewExpandDepthConverter, " + Consts.AssemblySystem_Web)]
278 public int ExpandDepth {
280 return ViewState.GetInt ("ExpandDepth", -1);
283 ViewState["ExpandDepth"] = value;
288 public string ExpandImageToolTip {
290 return ViewState.GetString ("ExpandImageToolTip", "Expand {0}");
293 ViewState["ExpandImageToolTip"] = value;
299 [WebSysDescription ("The url of the image to show when a node can be expanded.")]
300 [WebCategory ("Appearance")]
301 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
302 public string ExpandImageUrl {
304 return ViewState.GetString ("ExpandImageUrl", "");
307 ViewState["ExpandImageUrl"] = value;
311 [PersistenceMode (PersistenceMode.InnerProperty)]
312 [NotifyParentProperty (true)]
313 [DefaultValue (null)]
314 [WebCategory ("Styles")]
315 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
316 public Style HoverNodeStyle {
318 if (hoverNodeStyle == null) {
319 hoverNodeStyle = new Style();
320 if (IsTrackingViewState)
321 hoverNodeStyle.TrackViewState();
323 return hoverNodeStyle;
327 [DefaultValue (TreeViewImageSet.Custom)]
328 public TreeViewImageSet ImageSet {
330 return (TreeViewImageSet)ViewState.GetInt ("ImageSet", (int)TreeViewImageSet.Custom);
333 if (!Enum.IsDefined (typeof (TreeViewImageSet), value))
334 throw new ArgumentOutOfRangeException ();
335 ViewState["ImageSet"] = value;
339 [PersistenceMode (PersistenceMode.InnerProperty)]
340 [NotifyParentProperty (true)]
341 [DefaultValue (null)]
342 [WebCategory ("Styles")]
343 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
344 public TreeNodeStyle LeafNodeStyle {
346 if (leafNodeStyle == null) {
347 leafNodeStyle = new TreeNodeStyle ();
348 if (IsTrackingViewState)
349 leafNodeStyle.TrackViewState();
351 return leafNodeStyle;
355 [DefaultValue (null)]
356 [WebCategory ("Styles")]
357 [PersistenceMode (PersistenceMode.InnerProperty)]
358 [Editor ("System.Web.UI.Design.WebControls.TreeNodeStyleCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
359 public TreeNodeStyleCollection LevelStyles {
361 if (levelStyles == null) {
362 levelStyles = new TreeNodeStyleCollection ();
363 if (IsTrackingViewState)
364 ((IStateManager)levelStyles).TrackViewState();
371 public string LineImagesFolder {
373 return ViewState.GetString ("LineImagesFolder", "");
376 ViewState["LineImagesFolder"] = value;
381 public int MaxDataBindDepth {
383 return ViewState.GetInt ("MaxDataBindDepth", -1);
386 ViewState["MaxDataBindDepth"] = value;
391 public int NodeIndent {
393 return ViewState.GetInt ("NodeIndent", 20);
396 ViewState["NodeIndent"] = value;
400 [PersistenceMode (PersistenceMode.InnerProperty)]
401 [Editor ("System.Web.UI.Design.WebControls.TreeNodeCollectionEditor," + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
402 [DefaultValueAttribute (null)]
403 [MergablePropertyAttribute (false)]
404 public TreeNodeCollection Nodes {
407 nodes = new TreeNodeCollection (this);
408 if (IsTrackingViewState)
409 ((IStateManager)nodes).TrackViewState();
415 [PersistenceMode (PersistenceMode.InnerProperty)]
416 [NotifyParentProperty (true)]
417 [DefaultValue (null)]
418 [WebCategory ("Styles")]
419 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
420 public TreeNodeStyle NodeStyle {
422 if (nodeStyle == null) {
423 nodeStyle = new TreeNodeStyle ();
424 if (IsTrackingViewState)
425 nodeStyle.TrackViewState();
431 [DefaultValue (false)]
432 public bool NodeWrap {
434 return ViewState.GetBool ("NodeWrap", false);
437 ViewState ["NodeWrap"] = value;
443 [WebSysDescription ("The url of the image to show for leaf nodes.")]
444 [WebCategory ("Appearance")]
445 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
446 public string NoExpandImageUrl {
448 return ViewState.GetString ("NoExpandImageUrl", "");
451 ViewState ["NoExpandImageUrl"] = value;
455 [PersistenceMode (PersistenceMode.InnerProperty)]
456 [NotifyParentProperty (true)]
457 [DefaultValue (null)]
458 [WebCategory ("Styles")]
459 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
460 public TreeNodeStyle ParentNodeStyle {
462 if (parentNodeStyle == null) {
463 parentNodeStyle = new TreeNodeStyle ();
464 if (IsTrackingViewState)
465 parentNodeStyle.TrackViewState();
467 return parentNodeStyle;
472 public char PathSeparator {
474 return ViewState.GetChar ("PathSeparator", '/');
477 ViewState ["PathSeparator"] = value;
481 [DefaultValue (true)]
482 public bool PopulateNodesFromClient {
484 return ViewState.GetBool ("PopulateNodesFromClient", true);
487 ViewState ["PopulateNodesFromClient"] = value;
491 [PersistenceMode (PersistenceMode.InnerProperty)]
492 [NotifyParentProperty (true)]
493 [DefaultValue (null)]
494 [WebCategory ("Styles")]
495 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
496 public TreeNodeStyle RootNodeStyle {
498 if (rootNodeStyle == null) {
499 rootNodeStyle = new TreeNodeStyle ();
500 if (IsTrackingViewState)
501 rootNodeStyle.TrackViewState();
503 return rootNodeStyle;
507 [PersistenceMode (PersistenceMode.InnerProperty)]
508 [NotifyParentProperty (true)]
509 [DefaultValue (null)]
510 [WebCategory ("Styles")]
511 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
512 public TreeNodeStyle SelectedNodeStyle {
514 if (selectedNodeStyle == null) {
515 selectedNodeStyle = new TreeNodeStyle ();
516 if (IsTrackingViewState)
517 selectedNodeStyle.TrackViewState();
519 return selectedNodeStyle;
523 private Style ControlLinkStyle {
525 if (controlLinkStyle == null) {
526 controlLinkStyle = new Style ();
527 controlLinkStyle.AlwaysRenderTextDecoration = true;
529 return controlLinkStyle;
533 private Style NodeLinkStyle {
535 if (nodeLinkStyle == null) {
536 nodeLinkStyle = new Style ();
538 return nodeLinkStyle;
542 private Style RootNodeLinkStyle {
544 if (rootNodeLinkStyle == null) {
545 rootNodeLinkStyle = new Style ();
547 return rootNodeLinkStyle;
551 private Style ParentNodeLinkStyle {
553 if (parentNodeLinkStyle == null) {
554 parentNodeLinkStyle = new Style ();
556 return parentNodeLinkStyle;
560 private Style SelectedNodeLinkStyle {
562 if (selectedNodeLinkStyle == null) {
563 selectedNodeLinkStyle = new Style ();
565 return selectedNodeLinkStyle;
569 private Style LeafNodeLinkStyle {
571 if (leafNodeLinkStyle == null) {
572 leafNodeLinkStyle = new Style ();
574 return leafNodeLinkStyle;
578 private Style HoverNodeLinkStyle {
580 if (hoverNodeLinkStyle == null) {
581 hoverNodeLinkStyle = new Style ();
583 return hoverNodeLinkStyle;
587 [DefaultValue (TreeNodeTypes.None)]
588 public TreeNodeTypes ShowCheckBoxes {
590 return (TreeNodeTypes)ViewState.GetInt ("ShowCheckBoxes", (int)TreeNodeTypes.None);
594 throw new ArgumentOutOfRangeException ();
595 ViewState ["ShowCheckBoxes"] = value;
599 [DefaultValue (true)]
600 public bool ShowExpandCollapse {
602 return ViewState.GetBool ("ShowExpandCollapse", true);
605 ViewState ["ShowExpandCollapse"] = value;
609 [DefaultValue (false)]
610 public bool ShowLines {
612 return ViewState.GetBool ("ShowLines", false);
615 ViewState ["ShowLines"] = value;
620 public string SkipLinkText
623 return ViewState.GetString ("SkipLinkText", "Skip Navigation Links.");
626 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 : ""; }
645 public string Target {
647 return ViewState.GetString ("Target", "");
650 ViewState ["Target"] = value;
654 [MonoTODO ("why override?")]
655 public override bool Visible
661 base.Visible = value;
666 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
667 public TreeNodeCollection CheckedNodes {
669 TreeNodeCollection col = new TreeNodeCollection ();
670 FindCheckedNodes (Nodes, col);
675 void FindCheckedNodes (TreeNodeCollection nodeList, TreeNodeCollection result)
677 foreach (TreeNode node in nodeList) {
678 if (node.Checked) result.Add (node, false);
679 FindCheckedNodes (node.ChildNodes, result);
683 public void ExpandAll ()
685 foreach (TreeNode node in Nodes)
689 public void CollapseAll ()
691 foreach (TreeNode node in Nodes)
695 public TreeNode FindNode (string valuePath)
697 if (valuePath == null) throw new ArgumentNullException ("valuePath");
698 string[] path = valuePath.Split (PathSeparator);
700 TreeNodeCollection col = Nodes;
701 bool foundBranch = true;
702 while (col.Count > 0 && foundBranch) {
704 foreach (TreeNode node in col) {
705 if (node.Value == path [n]) {
706 if (++n == path.Length) return node;
707 col = node.ChildNodes;
716 ImageStyle GetImageStyle ()
718 if (ImageSet != TreeViewImageSet.Custom)
719 return (ImageStyle) imageStyles [ImageSet];
724 protected override HtmlTextWriterTag TagKey {
725 get { return HtmlTextWriterTag.Div; }
728 protected internal virtual TreeNode CreateNode ()
730 return new TreeNode (this);
733 public sealed override void DataBind ()
738 protected void SetNodeDataBound (TreeNode node, bool dataBound)
740 node.SetDataBound (dataBound);
743 protected void SetNodeDataPath (TreeNode node, string dataPath)
745 node.SetDataPath (dataPath);
748 protected void SetNodeDataItem (TreeNode node, object dataItem)
750 node.SetDataItem (dataItem);
753 protected internal override void OnInit (EventArgs e)
758 internal void SetSelectedNode (TreeNode node, bool loading)
760 if (selectedNode == node) return;
761 if (selectedNode != null)
762 selectedNode.SelectedFlag = false;
765 OnSelectedNodeChanged (new TreeNodeEventArgs (selectedNode));
768 internal void NotifyCheckChanged (TreeNode node)
770 OnTreeNodeCheckChanged (new TreeNodeEventArgs (node));
773 internal void NotifyExpandedChanged (TreeNode node)
775 if (node.Expanded.HasValue && node.Expanded.Value)
776 OnTreeNodeExpanded (new TreeNodeEventArgs (node));
777 else if (node.Expanded.HasValue && node.IsParentNode)
778 OnTreeNodeCollapsed (new TreeNodeEventArgs (node));
781 internal void NotifyPopulateRequired (TreeNode node)
783 OnTreeNodePopulate (new TreeNodeEventArgs (node));
786 protected override void TrackViewState()
790 base.TrackViewState();
791 if (hoverNodeStyle != null) {
792 hoverNodeStyle.TrackViewState();
794 if (leafNodeStyle != null) {
795 leafNodeStyle.TrackViewState();
797 if (levelStyles != null && levelStyles.Count > 0) {
798 ((IStateManager)levelStyles).TrackViewState();
800 if (nodeStyle != null) {
801 nodeStyle.TrackViewState();
803 if (parentNodeStyle != null) {
804 parentNodeStyle.TrackViewState();
806 if (rootNodeStyle != null) {
807 rootNodeStyle.TrackViewState();
809 if (selectedNodeStyle != null) {
810 selectedNodeStyle.TrackViewState();
812 if (dataBindings != null) {
813 ((IStateManager)dataBindings).TrackViewState ();
816 ((IStateManager)nodes).TrackViewState();;
820 protected override object SaveViewState()
822 object[] states = new object [10];
823 states[0] = base.SaveViewState();
824 states[1] = (hoverNodeStyle == null ? null : hoverNodeStyle.SaveViewState());
825 states[2] = (leafNodeStyle == null ? null : leafNodeStyle.SaveViewState());
826 states[3] = (levelStyles == null ? null : ((IStateManager)levelStyles).SaveViewState());
827 states[4] = (nodeStyle == null ? null : nodeStyle.SaveViewState());
828 states[5] = (parentNodeStyle == null ? null : parentNodeStyle.SaveViewState());
829 states[6] = (rootNodeStyle == null ? null : rootNodeStyle.SaveViewState());
830 states[7] = (selectedNodeStyle == null ? null : selectedNodeStyle.SaveViewState());
831 states[8] = (dataBindings == null ? null : ((IStateManager)dataBindings).SaveViewState());
832 states[9] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
834 for (int i = states.Length - 1; i >= 0; i--) {
835 if (states [i] != null)
842 protected override void LoadViewState (object savedState)
844 if (savedState == null)
847 object [] states = (object []) savedState;
848 base.LoadViewState (states[0]);
850 if (states[1] != null)
851 HoverNodeStyle.LoadViewState (states[1]);
852 if (states[2] != null)
853 LeafNodeStyle.LoadViewState(states[2]);
854 if (states[3] != null)
855 ((IStateManager)LevelStyles).LoadViewState(states[3]);
856 if (states[4] != null)
857 NodeStyle.LoadViewState(states[4]);
858 if (states[5] != null)
859 ParentNodeStyle.LoadViewState(states[5]);
860 if (states[6] != null)
861 RootNodeStyle.LoadViewState(states[6]);
862 if (states[7] != null)
863 SelectedNodeStyle.LoadViewState(states[7]);
864 if (states[8] != null)
865 ((IStateManager)DataBindings).LoadViewState(states[8]);
866 if (states[9] != null)
867 ((IStateManager)Nodes).LoadViewState(states[9]);
870 protected virtual void RaisePostBackEvent (string eventArgument)
872 string[] args = eventArgument.Split ('|');
873 TreeNode node = FindNodeByPos (args[1]);
874 if (node == null) return;
876 if (args [0] == "sel")
877 HandleSelectEvent (node);
878 else if (args [0] == "ec")
879 HandleExpandCollapseEvent (node);
882 void HandleSelectEvent (TreeNode node)
884 switch (node.SelectAction) {
885 case TreeNodeSelectAction.Select:
888 case TreeNodeSelectAction.Expand:
891 case TreeNodeSelectAction.SelectExpand:
898 void HandleExpandCollapseEvent (TreeNode node)
900 node.ToggleExpandState ();
903 protected virtual void RaisePostDataChangedEvent ()
907 string callbackResult;
908 protected virtual void RaiseCallbackEvent (string eventArgs)
910 RequiresDataBinding = true;
913 TreeNode node = FindNodeByPos (eventArgs);
914 ArrayList levelLines = new ArrayList ();
917 int childCount = nd.Parent != null ? nd.Parent.ChildNodes.Count : Nodes.Count;
918 levelLines.Insert (0, (nd.Index < childCount - 1) ? this : null);
922 StringWriter sw = new StringWriter ();
923 HtmlTextWriter writer = new HtmlTextWriter (sw);
924 EnsureStylesPrepared ();
926 node.Expanded = true;
927 int num = node.ChildNodes.Count;
928 for (int n=0; n<num; n++)
929 RenderNode (writer, node.ChildNodes [n], node.Depth + 1, levelLines, true, n<num-1);
931 string res = sw.ToString ();
932 callbackResult = res != "" ? res : "*";
935 protected virtual string GetCallbackResult ()
937 return callbackResult;
940 void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
942 RaisePostBackEvent (eventArgument);
945 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
947 return LoadPostData (postDataKey, postCollection);
950 void IPostBackDataHandler.RaisePostDataChangedEvent ()
952 RaisePostDataChangedEvent ();
955 void ICallbackEventHandler.RaiseCallbackEvent (string eventArgs)
957 RaiseCallbackEvent (eventArgs);
960 string ICallbackEventHandler.GetCallbackResult ()
962 return GetCallbackResult ();
965 protected override ControlCollection CreateControlCollection ()
967 return new EmptyControlCollection (this);
970 protected internal override void PerformDataBinding ()
972 base.PerformDataBinding ();
973 InitializeDataBindings ();
974 HierarchicalDataSourceView data = GetData ("");
978 IHierarchicalEnumerable e = data.Select ();
979 FillBoundChildrenRecursive (e, Nodes);
982 private void FillBoundChildrenRecursive (IHierarchicalEnumerable hEnumerable, TreeNodeCollection nodeCollection)
984 if (hEnumerable == null)
986 foreach (object obj in hEnumerable) {
987 IHierarchyData hdata = hEnumerable.GetHierarchyData (obj);
988 TreeNode child = new TreeNode ();
989 nodeCollection.Add (child);
991 OnTreeNodeDataBound (new TreeNodeEventArgs (child));
993 if (MaxDataBindDepth >= 0 && child.Depth == MaxDataBindDepth)
996 if (hdata == null || !hdata.HasChildren)
999 IHierarchicalEnumerable e = hdata.GetChildren ();
1000 FillBoundChildrenRecursive (e, child.ChildNodes);
1004 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
1008 if (EnableClientScript && PopulateNodesFromClient) {
1009 string states = postCollection [ClientID + "_PopulatedStates"];
1010 if (states != null) {
1011 foreach (string id in states.Split ('|')) {
1012 if (String.IsNullOrEmpty(id))
1014 TreeNode node = FindNodeByPos (id);
1015 if (node != null && node.PopulateOnDemand && !node.Populated)
1022 UnsetCheckStates (Nodes, postCollection);
1023 SetCheckStates (postCollection);
1025 if (EnableClientScript) {
1026 string states = postCollection [ClientID + "_ExpandStates"];
1027 if (states != null) {
1028 string[] ids = states.Split ('|');
1029 UnsetExpandStates (Nodes, ids);
1030 SetExpandStates (ids);
1033 UnsetExpandStates (Nodes, new string[0]);
1039 const string onPreRenderScript_1 = @"var {0} = new Object ();\n{0}.treeId = {1};\n{0}.uid = {2};\n{0}.showImage = {3};\n";
1040 const string onPreRenderScript_2 = @"{0}.form = {1};\n{0}.PopulateNode = function(nodeId) {{ {2}; }};\n{0}.populateFromClient = {3};\n{0}.expandAlt = {4};\n{0}.collapseAlt = {5};\n";
1042 protected internal override void OnPreRender (EventArgs e)
1044 base.OnPreRender (e);
1048 Page.RegisterRequiresPostBack (this);
1050 if (EnableClientScript && !Page.ClientScript.IsClientScriptIncludeRegistered (typeof(TreeView), "TreeView.js")) {
1051 string url = Page.ClientScript.GetWebResourceUrl (typeof(TreeView), "TreeView.js");
1052 Page.ClientScript.RegisterClientScriptInclude (typeof(TreeView), "TreeView.js", url);
1056 string ctree = ClientID + "_data";
1057 string script = String.Format (onPreRenderScript_1,
1059 ClientScriptManager.GetScriptLiteral (ClientID),
1060 ClientScriptManager.GetScriptLiteral (UniqueID),
1061 ClientScriptManager.GetScriptLiteral (ShowExpandCollapse));
1063 if (ShowExpandCollapse) {
1064 bool defaultImages = ShowLines || ImageSet != TreeViewImageSet.Custom || (ExpandImageUrl == "" && CollapseImageUrl == "");
1065 script += String.Concat (ctree, ".defaultImages = ", ClientScriptManager.GetScriptLiteral (defaultImages), ";\n");
1066 ImageStyle imageStyle = GetImageStyle ();
1067 if (!defaultImages) {
1068 script += String.Concat (ctree,
1070 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("plus", imageStyle)),
1072 script += String.Concat (ctree,
1073 ".collapseImage = ",
1074 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("minus", imageStyle)),
1077 if (PopulateNodesFromClient)
1078 script += String.Concat (ctree,
1079 ".noExpandImage = ",
1080 ClientScriptManager.GetScriptLiteral (GetNodeImageUrl ("noexpand", imageStyle)),
1085 script += String.Format (onPreRenderScript_2,
1088 Page.ClientScript.GetCallbackEventReference ("this.uid", "nodeId", "TreeView_PopulateCallback",
1089 "this.treeId + \" \" + nodeId",
1090 "TreeView_PopulateCallback", false),
1091 ClientScriptManager.GetScriptLiteral (PopulateNodesFromClient),
1092 ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (true, null)),
1093 ClientScriptManager.GetScriptLiteral (GetNodeImageToolTip (false, null)));
1095 if (!Page.IsPostBack) {
1096 SetNodesExpandedToDepthRecursive (Nodes);
1099 if (EnableClientScript) {
1100 Page.ClientScript.RegisterHiddenField (ClientID + "_ExpandStates", GetExpandStates ());
1102 // Make sure the basic script infrastructure is rendered
1103 Page.ClientScript.RegisterWebFormClientScript ();
1106 if (EnableClientScript && PopulateNodesFromClient) {
1107 Page.ClientScript.RegisterHiddenField (ClientID + "_PopulatedStates", "|");
1110 EnsureStylesPrepared ();
1112 if (hoverNodeStyle != null) {
1113 if (Page.Header == null)
1114 throw new InvalidOperationException ("Using TreeView.HoverNodeStyle requires Page.Header to be non-null (e.g. <head runat=\"server\" />).");
1115 RegisterStyle (HoverNodeStyle, HoverNodeLinkStyle);
1116 script += String.Concat (ctree, ".hoverClass = ",
1117 ClientScriptManager.GetScriptLiteral (HoverNodeStyle.RegisteredCssClass),
1119 script += String.Concat (ctree, ".hoverLinkClass = ",
1120 ClientScriptManager.GetScriptLiteral (HoverNodeLinkStyle.RegisteredCssClass),
1124 Page.ClientScript.RegisterStartupScript (typeof(TreeView), this.UniqueID, script, true);
1128 void EnsureStylesPrepared () {
1131 stylesPrepared = true;
1135 private void PrepareStyles () {
1136 // The order in which styles are defined matters when more than one class
1137 // is assigned to an element
1138 ControlLinkStyle.CopyTextStylesFrom (ControlStyle);
1139 RegisterStyle (ControlLinkStyle);
1141 if (nodeStyle != null)
1142 RegisterStyle (NodeStyle, NodeLinkStyle);
1144 if (rootNodeStyle != null)
1145 RegisterStyle (RootNodeStyle, RootNodeLinkStyle);
1147 if (parentNodeStyle != null)
1148 RegisterStyle (ParentNodeStyle, ParentNodeLinkStyle);
1150 if (leafNodeStyle != null)
1151 RegisterStyle (LeafNodeStyle, LeafNodeLinkStyle);
1154 if (levelStyles != null && levelStyles.Count > 0) {
1155 levelLinkStyles = new List<Style> (levelStyles.Count);
1156 foreach (Style style in levelStyles) {
1157 Style linkStyle = new Style ();
1158 levelLinkStyles.Add (linkStyle);
1159 RegisterStyle (style, linkStyle);
1163 if (selectedNodeStyle != null)
1164 RegisterStyle (SelectedNodeStyle, SelectedNodeLinkStyle);
1167 void SetNodesExpandedToDepthRecursive (TreeNodeCollection nodes) {
1168 foreach (TreeNode node in nodes) {
1169 if (!node.Expanded.HasValue) {
1170 if (ExpandDepth < 0 || node.Depth < ExpandDepth)
1171 node.Expanded = true;
1173 SetNodesExpandedToDepthRecursive (node.ChildNodes);
1177 string IncrementStyleClassName () {
1178 registeredStylesCounter++;
1179 return ClientID + "_" + registeredStylesCounter;
1182 void RegisterStyle (Style baseStyle, Style linkStyle) {
1183 linkStyle.CopyTextStylesFrom (baseStyle);
1184 linkStyle.BorderStyle = BorderStyle.None;
1185 baseStyle.Font.Reset ();
1186 RegisterStyle (linkStyle);
1187 RegisterStyle (baseStyle);
1190 void RegisterStyle (Style baseStyle) {
1191 if (Page.Header == null)
1193 string className = IncrementStyleClassName ().Trim ('_');
1194 baseStyle.SetRegisteredCssClass (className);
1195 Page.Header.StyleSheet.CreateStyleRule (baseStyle, this, "." + className);
1198 string GetBindingKey (string dataMember, int depth)
1200 return dataMember + " " + depth;
1203 void InitializeDataBindings () {
1204 if (dataBindings != null && dataBindings.Count > 0) {
1205 bindings = new Hashtable ();
1206 foreach (TreeNodeBinding bin in dataBindings) {
1207 string key = GetBindingKey (bin.DataMember, bin.Depth);
1208 bindings [key] = bin;
1215 internal TreeNodeBinding FindBindingForNode (string type, int depth)
1217 if (bindings == null)
1220 TreeNodeBinding bin = (TreeNodeBinding) bindings [GetBindingKey (type, depth)];
1221 if (bin != null) return bin;
1223 bin = (TreeNodeBinding) bindings [GetBindingKey (type, -1)];
1224 if (bin != null) return bin;
1226 bin = (TreeNodeBinding) bindings [GetBindingKey ("", depth)];
1227 if (bin != null) return bin;
1229 return (TreeNodeBinding) bindings [GetBindingKey ("", -1)];
1232 internal void DecorateNode(TreeNode node)
1237 if (node.ImageUrl != null && node.ImageUrl.Length > 0)
1240 if (node.IsRootNode && rootNodeStyle != null) {
1241 node.ImageUrl = rootNodeStyle.ImageUrl;
1244 if (node.IsParentNode && parentNodeStyle != null) {
1245 node.ImageUrl = parentNodeStyle.ImageUrl;
1248 if (node.IsLeafNode && leafNodeStyle != null)
1249 node.ImageUrl = leafNodeStyle.ImageUrl;
1252 protected internal override void RenderContents (HtmlTextWriter writer)
1254 ArrayList levelLines = new ArrayList ();
1255 int num = Nodes.Count;
1256 for (int n=0; n<num; n++)
1257 RenderNode (writer, Nodes [n], 0, levelLines, n>0, n<num-1);
1260 protected override void AddAttributesToRender(HtmlTextWriter writer)
1262 base.AddAttributesToRender (writer);
1265 public override void RenderBeginTag (HtmlTextWriter writer)
1267 if (SkipLinkText != "") {
1268 writer.AddAttribute (HtmlTextWriterAttribute.Href, "#" + ClientID + "_SkipLink");
1269 writer.RenderBeginTag (HtmlTextWriterTag.A);
1271 Image img = new Image ();
1272 ClientScriptManager csm = new ClientScriptManager (null);
1273 img.ImageUrl = csm.GetWebResourceUrl (typeof (SiteMapPath), "transparent.gif");
1274 img.Attributes.Add ("height", "0");
1275 img.Attributes.Add ("width", "0");
1276 img.AlternateText = SkipLinkText;
1277 img.Render (writer);
1279 writer.RenderEndTag ();
1281 base.RenderBeginTag (writer);
1284 public override void RenderEndTag (HtmlTextWriter writer)
1286 base.RenderEndTag (writer);
1288 if (SkipLinkText != "") {
1289 writer.AddAttribute (HtmlTextWriterAttribute.Id, ClientID + "_SkipLink");
1290 writer.RenderBeginTag (HtmlTextWriterTag.A);
1291 writer.RenderEndTag ();
1295 void RenderNode (HtmlTextWriter writer, TreeNode node, int level, ArrayList levelLines, bool hasPrevious, bool hasNext)
1300 bool clientExpand = EnableClientScript && Events [TreeNodeCollapsedEvent] == null && Events [TreeNodeExpandedEvent] == null;
1301 ImageStyle imageStyle = GetImageStyle ();
1302 bool renderChildNodes = node.Expanded.HasValue && node.Expanded.Value;
1304 if (clientExpand && !renderChildNodes)
1305 renderChildNodes = (!node.PopulateOnDemand || node.Populated);
1309 if (renderChildNodes)
1310 hasChildNodes = node.ChildNodes.Count > 0;
1312 hasChildNodes = (node.PopulateOnDemand && !node.Populated) || node.ChildNodes.Count > 0;
1314 writer.AddAttribute ("cellpadding", "0", false);
1315 writer.AddAttribute ("cellspacing", "0", false);
1316 writer.AddStyleAttribute ("border-width", "0");
1317 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1319 Unit nodeSpacing = GetNodeSpacing (node);
1321 if (nodeSpacing != Unit.Empty && (node.Depth > 0 || node.Index > 0))
1322 RenderMenuItemSpacing (writer, nodeSpacing);
1324 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1326 // Vertical lines from previous levels
1328 nodeImage = GetNodeImageUrl ("i", imageStyle);
1329 for (int n=0; n<level; n++) {
1330 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1331 writer.AddStyleAttribute ("width", NodeIndent + "px");
1332 writer.AddStyleAttribute ("height", "1px");
1333 writer.RenderBeginTag (HtmlTextWriterTag.Div);
1334 if (ShowLines && levelLines [n] != null) {
1335 writer.AddAttribute ("src", nodeImage);
1336 writer.AddAttribute (HtmlTextWriterAttribute.Alt, "", false);
1337 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1338 writer.RenderEndTag ();
1340 writer.RenderEndTag ();
1341 writer.RenderEndTag (); // TD
1344 // Node image + line
1346 if (ShowExpandCollapse || ShowLines) {
1347 bool buttonImage = false;
1348 string tooltip = "";
1352 if (hasPrevious && hasNext) shape = "t";
1353 else if (hasPrevious && !hasNext) shape = "l";
1354 else if (!hasPrevious && hasNext) shape = "r";
1355 else shape = "dash";
1358 if (ShowExpandCollapse) {
1359 if (hasChildNodes) {
1361 if (node.Expanded.HasValue && node.Expanded.Value) shape += "minus";
1362 else shape += "plus";
1363 tooltip = GetNodeImageToolTip (!(node.Expanded.HasValue && node.Expanded.Value), node.Text);
1364 } else if (!ShowLines)
1369 nodeImage = GetNodeImageUrl (shape, imageStyle);
1370 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1373 if (!clientExpand || (!PopulateNodesFromClient && node.PopulateOnDemand && !node.Populated))
1374 writer.AddAttribute ("href", GetClientEvent (node, "ec"));
1376 writer.AddAttribute ("href", GetClientExpandEvent(node));
1377 writer.RenderBeginTag (HtmlTextWriterTag.A); // Anchor
1380 writer.AddAttribute ("alt", tooltip);
1382 if (buttonImage && clientExpand)
1383 writer.AddAttribute ("id", GetNodeClientId (node, "img"));
1384 writer.AddAttribute ("src", nodeImage);
1386 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1387 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1388 writer.RenderEndTag ();
1391 writer.RenderEndTag (); // Anchor
1393 writer.RenderEndTag (); // TD
1399 string imageUrl = node.ImageUrl.Length > 0 ? ResolveClientUrl (node.ImageUrl) : null;
1400 if (String.IsNullOrEmpty (imageUrl) && imageStyle != null) {
1401 if (imageStyle.RootIcon != null && node.IsRootNode)
1402 imageUrl = GetNodeIconUrl (imageStyle.RootIcon);
1403 else if (imageStyle.ParentIcon != null && node.IsParentNode)
1404 imageUrl = GetNodeIconUrl (imageStyle.ParentIcon);
1405 else if (imageStyle.LeafIcon != null && node.IsLeafNode)
1406 imageUrl = GetNodeIconUrl (imageStyle.LeafIcon);
1409 if (level < LevelStyles.Count && LevelStyles [level].ImageUrl != null)
1410 imageUrl = ResolveClientUrl (LevelStyles [level].ImageUrl);
1412 if (!String.IsNullOrEmpty (imageUrl)) {
1413 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1414 BeginNodeTag (writer, node, clientExpand);
1415 writer.AddAttribute ("src", imageUrl);
1416 writer.AddStyleAttribute (HtmlTextWriterStyle.BorderWidth, "0");
1417 writer.AddAttribute ("alt", node.ImageToolTip);
1418 writer.RenderBeginTag (HtmlTextWriterTag.Img);
1419 writer.RenderEndTag (); // IMG
1420 writer.RenderEndTag (); // style tag
1421 writer.RenderEndTag (); // TD
1425 writer.AddStyleAttribute ("white-space", "nowrap");
1426 AddNodeStyle (writer, node, level);
1427 if (EnableClientScript) {
1428 writer.AddAttribute ("onmouseout", "TreeView_UnhoverNode(this)", false);
1429 writer.AddAttribute ("onmouseover", "TreeView_HoverNode('" + ClientID + "', this)");
1431 writer.RenderBeginTag (HtmlTextWriterTag.Td); // TD
1435 if (node.ShowCheckBoxInternal) {
1436 writer.AddAttribute ("name", ClientID + "_cs_" + node.Path);
1437 writer.AddAttribute ("type", "checkbox", false);
1438 writer.AddAttribute ("title", node.Text);
1439 if (node.Checked) writer.AddAttribute ("checked", "checked", false);
1440 writer.RenderBeginTag (HtmlTextWriterTag.Input); // INPUT
1441 writer.RenderEndTag (); // INPUT
1446 node.BeginRenderText (writer);
1449 writer.AddAttribute ("id", GetNodeClientId (node, "txt"));
1450 AddNodeLinkStyle (writer, node, level);
1451 BeginNodeTag (writer, node, clientExpand);
1452 writer.Write (node.Text);
1453 writer.RenderEndTag (); // style tag
1455 node.EndRenderText (writer);
1457 writer.RenderEndTag (); // TD
1459 writer.RenderEndTag (); // TR
1461 if (nodeSpacing != Unit.Empty)
1462 RenderMenuItemSpacing (writer, nodeSpacing);
1464 writer.RenderEndTag (); // TABLE
1468 if (hasChildNodes) {
1469 if (level >= levelLines.Count) {
1471 levelLines.Add (this);
1473 levelLines.Add (null);
1476 levelLines [level] = this;
1478 levelLines [level] = null;
1482 if (!(node.Expanded.HasValue && node.Expanded.Value))
1483 writer.AddStyleAttribute ("display", "none");
1485 writer.AddStyleAttribute ("display", "block");
1486 writer.AddAttribute ("id", GetNodeClientId (node, null));
1487 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1489 if (renderChildNodes) {
1490 AddChildrenPadding (writer, node);
1491 int num = node.ChildNodes.Count;
1492 for (int n=0; n<num; n++)
1493 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1495 AddChildrenPadding (writer, node);
1497 writer.RenderEndTag (); // SPAN
1498 } else if (renderChildNodes) {
1499 AddChildrenPadding (writer, node);
1500 int num = node.ChildNodes.Count;
1501 for (int n=0; n<num; n++)
1502 RenderNode (writer, node.ChildNodes [n], level + 1, levelLines, true, n<num-1);
1504 AddChildrenPadding (writer, node);
1509 private void AddChildrenPadding (HtmlTextWriter writer, TreeNode node)
1511 int level = node.Depth;
1512 Unit cnp = Unit.Empty;
1514 if (levelStyles != null && level < levelStyles.Count)
1515 cnp = levelStyles [level].ChildNodesPadding;
1516 if (cnp.IsEmpty && nodeStyle != null)
1517 cnp = nodeStyle.ChildNodesPadding;
1520 if (cnp.IsEmpty || (value = cnp.Value) == 0 || cnp.Type != UnitType.Pixel)
1523 writer.RenderBeginTag (HtmlTextWriterTag.Table);
1524 writer.AddAttribute ("height", ((int) value).ToString (), false);
1525 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1526 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1527 writer.RenderEndTag (); // td
1528 writer.RenderEndTag (); // tr
1529 writer.RenderEndTag (); // table
1532 private void RenderMenuItemSpacing (HtmlTextWriter writer, Unit itemSpacing) {
1533 writer.AddStyleAttribute ("height", itemSpacing.ToString ());
1534 writer.RenderBeginTag (HtmlTextWriterTag.Tr);
1535 writer.RenderBeginTag (HtmlTextWriterTag.Td);
1536 writer.RenderEndTag ();
1537 writer.RenderEndTag ();
1540 private Unit GetNodeSpacing (TreeNode node) {
1541 if (node.Selected && selectedNodeStyle != null && selectedNodeStyle.NodeSpacing != Unit.Empty) {
1542 return selectedNodeStyle.NodeSpacing;
1545 if (levelStyles != null && node.Depth < levelStyles.Count && levelStyles [node.Depth].NodeSpacing != Unit.Empty) {
1546 return levelStyles [node.Depth].NodeSpacing;
1549 if (node.IsLeafNode) {
1550 if (leafNodeStyle != null && leafNodeStyle.NodeSpacing != Unit.Empty)
1551 return leafNodeStyle.NodeSpacing;
1553 else if (node.IsRootNode) {
1554 if (rootNodeStyle != null && rootNodeStyle.NodeSpacing != Unit.Empty)
1555 return rootNodeStyle.NodeSpacing;
1557 else if (node.IsParentNode) {
1558 if (parentNodeStyle != null && parentNodeStyle.NodeSpacing != Unit.Empty)
1559 return parentNodeStyle.NodeSpacing;
1562 if (nodeStyle != null)
1563 return nodeStyle.NodeSpacing;
1568 void AddNodeStyle (HtmlTextWriter writer, TreeNode node, int level)
1570 TreeNodeStyle style = new TreeNodeStyle ();
1571 if (Page.Header != null) {
1572 // styles are registered
1573 if (nodeStyle != null) {
1574 style.AddCssClass (nodeStyle.CssClass);
1575 style.AddCssClass (nodeStyle.RegisteredCssClass);
1577 if (node.IsLeafNode) {
1578 if (leafNodeStyle != null) {
1579 style.AddCssClass (leafNodeStyle.CssClass);
1580 style.AddCssClass (leafNodeStyle.RegisteredCssClass);
1583 else if (node.IsRootNode) {
1584 if (rootNodeStyle != null) {
1585 style.AddCssClass (rootNodeStyle.CssClass);
1586 style.AddCssClass (rootNodeStyle.RegisteredCssClass);
1589 else if (node.IsParentNode) {
1590 if (parentNodeStyle != null) {
1591 style.AddCssClass (parentNodeStyle.CssClass);
1592 style.AddCssClass (parentNodeStyle.RegisteredCssClass);
1595 if (levelStyles != null && levelStyles.Count > level) {
1596 style.AddCssClass (levelStyles [level].CssClass);
1597 style.AddCssClass (levelStyles [level].RegisteredCssClass);
1599 if (node == SelectedNode && selectedNodeStyle != null) {
1600 style.AddCssClass (selectedNodeStyle.CssClass);
1601 style.AddCssClass (selectedNodeStyle.RegisteredCssClass);
1605 // styles are not registered
1606 if (nodeStyle != null) {
1607 style.CopyFrom (nodeStyle);
1609 if (node.IsLeafNode) {
1610 if (leafNodeStyle != null) {
1611 style.CopyFrom (leafNodeStyle);
1614 else if (node.IsRootNode) {
1615 if (rootNodeStyle != null) {
1616 style.CopyFrom (rootNodeStyle);
1619 else if (node.IsParentNode) {
1620 if (parentNodeStyle != null) {
1621 style.CopyFrom (parentNodeStyle);
1624 if (levelStyles != null && levelStyles.Count > level) {
1625 style.CopyFrom (levelStyles [level]);
1627 if (node == SelectedNode && selectedNodeStyle != null) {
1628 style.CopyFrom (selectedNodeStyle);
1631 style.AddAttributesToRender (writer);
1634 void AddNodeLinkStyle (HtmlTextWriter writer, TreeNode node, int level) {
1635 Style style = new Style ();
1636 if (Page.Header != null) {
1637 // styles are registered
1638 style.AddCssClass (ControlLinkStyle.RegisteredCssClass);
1640 if (nodeStyle != null) {
1641 style.AddCssClass (nodeLinkStyle.CssClass);
1642 style.AddCssClass (nodeLinkStyle.RegisteredCssClass);
1644 if (node.IsLeafNode) {
1645 if (leafNodeStyle != null) {
1646 style.AddCssClass (leafNodeLinkStyle.CssClass);
1647 style.AddCssClass (leafNodeLinkStyle.RegisteredCssClass);
1650 else if (node.IsRootNode) {
1651 if (rootNodeStyle != null) {
1652 style.AddCssClass (rootNodeLinkStyle.CssClass);
1653 style.AddCssClass (rootNodeLinkStyle.RegisteredCssClass);
1656 else if (node.IsParentNode) {
1657 if (parentNodeStyle != null) {
1658 style.AddCssClass (parentNodeLinkStyle.CssClass);
1659 style.AddCssClass (parentNodeLinkStyle.RegisteredCssClass);
1662 if (levelStyles != null && levelStyles.Count > level) {
1663 style.AddCssClass (levelLinkStyles [level].CssClass);
1664 style.AddCssClass (levelLinkStyles [level].RegisteredCssClass);
1666 if (node == SelectedNode && selectedNodeStyle != null) {
1667 style.AddCssClass (selectedNodeLinkStyle.CssClass);
1668 style.AddCssClass (selectedNodeLinkStyle.RegisteredCssClass);
1672 // styles are not registered
1673 style.CopyFrom (ControlLinkStyle);
1674 if (nodeStyle != null) {
1675 style.CopyFrom (nodeLinkStyle);
1677 if (node.IsLeafNode) {
1678 if (node.IsLeafNode && leafNodeStyle != null) {
1679 style.CopyFrom (leafNodeLinkStyle);
1682 else if (node.IsRootNode) {
1683 if (node.IsRootNode && rootNodeStyle != null) {
1684 style.CopyFrom (rootNodeLinkStyle);
1687 else if (node.IsParentNode) {
1688 if (node.IsParentNode && parentNodeStyle != null) {
1689 style.CopyFrom (parentNodeLinkStyle);
1692 if (levelStyles != null && levelStyles.Count > level) {
1693 style.CopyFrom (levelLinkStyles [level]);
1695 if (node == SelectedNode && selectedNodeStyle != null) {
1696 style.CopyFrom (selectedNodeLinkStyle);
1698 style.AlwaysRenderTextDecoration = true;
1700 style.AddAttributesToRender (writer);
1703 void BeginNodeTag (HtmlTextWriter writer, TreeNode node, bool clientExpand)
1705 if(node.ToolTip.Length>0)
1706 writer.AddAttribute ("title", node.ToolTip);
1708 if (node.NavigateUrl != "") {
1709 string target = node.Target.Length > 0 ? node.Target : Target;
1711 string navUrl = ResolveClientUrl (node.NavigateUrl, String.Compare (target, "_blank", StringComparison.InvariantCultureIgnoreCase) != 0);
1713 string navUrl = ResolveClientUrl (node.NavigateUrl);
1715 writer.AddAttribute ("href", navUrl);
1716 if (target.Length > 0)
1717 writer.AddAttribute ("target", target);
1718 writer.RenderBeginTag (HtmlTextWriterTag.A);
1720 else if (node.SelectAction != TreeNodeSelectAction.None) {
1721 if (node.SelectAction == TreeNodeSelectAction.Expand && clientExpand)
1722 writer.AddAttribute ("href", GetClientExpandEvent (node));
1724 writer.AddAttribute ("href", GetClientEvent (node, "sel"));
1725 writer.RenderBeginTag (HtmlTextWriterTag.A);
1728 writer.RenderBeginTag (HtmlTextWriterTag.Span);
1731 string GetNodeImageToolTip (bool expand, string txt) {
1733 if (ExpandImageToolTip != "")
1734 return String.Format (ExpandImageToolTip, txt);
1735 else if (txt != null)
1736 return "Expand " + txt;
1738 return "Expand {0}";
1740 if (CollapseImageToolTip != "")
1741 return String.Format (CollapseImageToolTip, txt);
1742 else if (txt != null)
1743 return "Collapse " + txt;
1745 return "Collapse {0}";
1749 string GetNodeClientId (TreeNode node, string sufix)
1751 return ClientID + "_" + node.Path + (sufix != null ? "_" + sufix : "");
1754 string GetNodeImageUrl (string shape, ImageStyle imageStyle)
1757 if (!String.IsNullOrEmpty (LineImagesFolder))
1758 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1760 if (imageStyle != null) {
1761 if (shape == "plus") {
1762 if (!String.IsNullOrEmpty (imageStyle.Expand))
1763 return GetNodeIconUrl (imageStyle.Expand);
1765 else if (shape == "minus") {
1766 if (!String.IsNullOrEmpty (imageStyle.Collapse))
1767 return GetNodeIconUrl (imageStyle.Collapse);
1769 else if (shape == "noexpand") {
1770 if (!String.IsNullOrEmpty (imageStyle.NoExpand))
1771 return GetNodeIconUrl (imageStyle.NoExpand);
1775 if (shape == "plus") {
1776 if (!String.IsNullOrEmpty (ExpandImageUrl))
1777 return ResolveClientUrl (ExpandImageUrl);
1779 else if (shape == "minus") {
1780 if (!String.IsNullOrEmpty (CollapseImageUrl))
1781 return ResolveClientUrl (CollapseImageUrl);
1783 else if (shape == "noexpand") {
1784 if (!String.IsNullOrEmpty (NoExpandImageUrl))
1785 return ResolveClientUrl (NoExpandImageUrl);
1788 if (!String.IsNullOrEmpty (LineImagesFolder))
1789 return ResolveClientUrl (LineImagesFolder + "/" + shape + ".gif");
1791 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), "TreeView_" + shape + ".gif");
1794 string GetNodeIconUrl (string icon)
1796 return Page.ClientScript.GetWebResourceUrl (typeof (TreeView), icon + ".gif");
1799 string GetClientEvent (TreeNode node, string ev)
1801 return Page.ClientScript.GetPostBackClientHyperlink (this, ev + "|" + node.Path, true);
1804 string GetClientExpandEvent (TreeNode node)
1806 return "javascript:TreeView_ToggleExpand ('" + ClientID + "', '" + node.Path + "')";
1809 TreeNode FindNodeByPos (string path)
1811 string[] indexes = path.Split ('_');
1812 TreeNode node = null;
1814 foreach (string index in indexes) {
1815 int i = int.Parse (index);
1817 if (i >= Nodes.Count) return null;
1820 if (i >= node.ChildNodes.Count) return null;
1821 node = node.ChildNodes [i];
1827 void UnsetCheckStates (TreeNodeCollection col, NameValueCollection states)
1829 foreach (TreeNode node in col) {
1830 if (node.ShowCheckBoxInternal && node.Checked) {
1831 if (states == null || states [ClientID + "_cs_" + node.Path] == null)
1832 node.Checked = false;
1834 if (node.HasChildData)
1835 UnsetCheckStates (node.ChildNodes, states);
1839 void SetCheckStates (NameValueCollection states)
1844 string keyPrefix = ClientID + "_cs_";
1845 foreach (string key in states) {
1846 if (key.StartsWith (keyPrefix, StringComparison.Ordinal)) {
1847 string id = key.Substring (keyPrefix.Length);
1848 TreeNode node = FindNodeByPos (id);
1849 if (node != null && !node.Checked)
1850 node.Checked = true;
1855 void UnsetExpandStates (TreeNodeCollection col, string[] states)
1857 foreach (TreeNode node in col) {
1858 if (node.Expanded.HasValue && node.Expanded.Value) {
1859 bool expand = (Array.IndexOf (states, node.Path) != -1);
1860 if (!expand) node.Expanded = false;
1862 if (node.HasChildData)
1863 UnsetExpandStates (node.ChildNodes, states);
1867 void SetExpandStates (string[] states)
1869 foreach (string id in states) {
1870 if (id == null || id == "") continue;
1871 TreeNode node = FindNodeByPos (id);
1873 node.Expanded = true;
1877 string GetExpandStates ()
1879 StringBuilder sb = new StringBuilder ("|");
1881 foreach (TreeNode node in Nodes)
1882 GetExpandStates (sb, node);
1884 return sb.ToString ();
1887 void GetExpandStates (StringBuilder sb, TreeNode node)
1889 if (node.Expanded.HasValue && node.Expanded.Value) {
1890 sb.Append (node.Path);
1893 if (node.HasChildData) {
1894 foreach (TreeNode child in node.ChildNodes)
1895 GetExpandStates (sb, child);