Merge pull request #4540 from kumpera/android-changes-part1
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / TreeNode.cs
1 //
2 // System.Web.UI.WebControls.TreeNode.cs
3 //
4 // Authors:
5 //      Lluis Sanchez Gual (lluis@novell.com)
6 //
7 // (C) 2004 Novell, Inc (http://www.novell.com)
8 //
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:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
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.
27 //
28 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
29 //
30
31
32 using System;
33 using System.Collections;
34 using System.Text;
35 using System.ComponentModel;
36 using System.Web.UI;
37
38 namespace System.Web.UI.WebControls
39 {
40         [ParseChildrenAttribute (true, "ChildNodes")]
41         public class TreeNode: IStateManager, ICloneable
42         {
43                 StateBag ViewState = new StateBag ();
44                 TreeNodeCollection nodes;
45                 bool marked;
46                 TreeView tree;
47                 TreeNode parent;
48                 int index;
49                 string path;
50                 int depth = -1;
51                 
52                 object dataItem;
53                 IHierarchyData hierarchyData;
54
55                 bool gotBinding;
56                 TreeNodeBinding binding;
57                 PropertyDescriptorCollection boundProperties;
58                 bool populating;
59                 bool hadChildrenBeforePopulating;
60                 
61                 internal TreeNode (TreeView tree)
62                 {
63                         Tree = tree;
64                 }
65                 
66                 public TreeNode ()
67                 {
68                 }
69                 
70                 public TreeNode (string text)
71                 {
72                         Text = text;
73                 }
74                 
75                 public TreeNode (string text, string value)
76                 {
77                         Text = text;
78                         Value = value;
79                 }
80                 
81                 public TreeNode (string text, string value, string imageUrl)
82                 {
83                         Text = text;
84                         Value = value;
85                         ImageUrl = imageUrl;
86                 }
87                 
88                 public TreeNode (string text, string value, string imageUrl, string navigateUrl, string target)
89                 {
90                         Text = text;
91                         Value = value;
92                         ImageUrl = imageUrl;
93                         NavigateUrl = navigateUrl;
94                         Target = target;
95                 }
96                 
97                 [MonoTODO ("Not implemented")]
98                 protected TreeNode (TreeView owner, bool isRoot)
99                 {
100                         throw new NotImplementedException ();
101                 }
102
103                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
104                 [Browsable (false)]
105                 public int Depth {
106                         get {
107                                 if (depth != -1) return depth;
108                                 depth = 0;
109                                 TreeNode nod = parent;
110                                 while (nod != null) {
111                                         depth++;
112                                         nod = nod.parent;
113                                 }
114                                 return depth;
115                         }
116                 }
117                 
118                 void ResetPathData ()
119                 {
120                         path = null;
121                         depth = -1;
122                         gotBinding = false;
123                         if (nodes != null) {
124                                 foreach (TreeNode node in nodes)
125                                         node.ResetPathData ();
126                         }
127                 }
128                 
129                 internal TreeView Tree {
130                         get { return tree; }
131                         set {
132                                 if (SelectedFlag) {
133                                         if (value != null)
134                                                 value.SetSelectedNode (this, false);
135                                 }
136                                 tree = value;
137                                 if (nodes != null)
138                                         nodes.SetTree (tree);
139                                 ResetPathData ();
140                                 if (PopulateOnDemand && !Populated && Expanded.HasValue && Expanded.Value)
141                                         Populate ();
142                         }
143                 }
144                 
145                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
146                 [DefaultValue (false)]
147                 [Browsable (false)]
148                 public bool DataBound {
149                         get { return ViewState ["DataBound"] == null ? false : (bool) ViewState ["DataBound"]; }
150                         private set { ViewState ["DataBound"] = value; }
151                 }
152                 
153                 [DefaultValue (null)]
154                 [Browsable (false)]
155                 public object DataItem {
156                         get { return dataItem; }
157                 }
158                 
159                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
160                 [DefaultValue ("")]
161                 [Browsable (false)]
162                 public string DataPath {
163                         get { return ViewState ["DataPath"] == null ? String.Empty : (String) ViewState ["DataPath"]; }
164                         private set { ViewState ["DataPath"] = value; }
165                 }
166                 
167                 [DefaultValue (false)]
168                 public bool Checked {
169                         get {
170                                 object o = ViewState ["Checked"];
171                                 if (o != null) return (bool)o;
172                                 return false;
173                         }
174                         set {
175                                 ViewState ["Checked"] = value;
176                                 if (tree != null)
177                                         tree.NotifyCheckChanged (this);
178                         }
179                 }
180
181                 [DefaultValue (null)]
182                 [MergableProperty (false)]
183                 [Browsable (false)]
184                 [PersistenceMode (PersistenceMode.InnerDefaultProperty)]
185                 public TreeNodeCollection ChildNodes {
186                         get {
187                                 if (nodes == null) {
188                                         nodes = new TreeNodeCollection (this);
189                                                 
190                                         if (IsTrackingViewState)
191                                                 ((IStateManager)nodes).TrackViewState();
192                                 }
193                                 return nodes;
194                         }
195                 }
196                 
197                 [DefaultValue (null)]
198                 public bool? Expanded {
199                         get {
200                                 object o = ViewState ["Expanded"];
201                                 return (bool?)o;
202                         }
203                         set {
204                                 bool? current = (bool?) ViewState ["Expanded"];
205                                 if (current == value)
206                                         return;
207                                 ViewState ["Expanded"] = value;
208                                 if (tree != null)
209                                         tree.NotifyExpandedChanged (this);
210                                 if (PopulateOnDemand && !Populated && value.HasValue && value.Value)
211                                         Populate ();
212                         }
213                 }
214
215                 [Localizable (true)]
216                 [DefaultValue ("")]
217                 public string ImageToolTip {
218                         get {
219                                 object o = ViewState ["ImageToolTip"];
220                                 if (o != null)
221                                         return (string)o;
222                                 return String.Empty;
223                         }
224                         set { ViewState ["ImageToolTip"] = value; }
225                 }
226                 
227                 [DefaultValue ("")]
228                 [UrlProperty]
229                 [Editor ("System.Web.UI.Design.ImageUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
230                 public string ImageUrl {
231                         get {
232                                 object o = ViewState ["ImageUrl"];
233                                 if (o != null)
234                                         return (string)o;
235                                 return String.Empty;
236                         }
237                         set { ViewState ["ImageUrl"] = value; }
238                 }
239
240                 [DefaultValue ("")]
241                 [UrlProperty]
242                 [Editor ("System.Web.UI.Design.UrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
243                 public string NavigateUrl {
244                         get {
245                                 object o = ViewState ["NavigateUrl"];
246                                 if (o != null)
247                                         return (string)o;
248                                 return String.Empty;
249                         }
250                         set { ViewState ["NavigateUrl"] = value; }
251                 }
252
253                 internal bool HadChildrenBeforePopulating {
254                         get { return hadChildrenBeforePopulating; }
255                         set {
256                                 if (populating)
257                                         return;
258
259                                 hadChildrenBeforePopulating = value;
260                         }
261                 }
262                 
263                 [DefaultValue (false)]
264                 public bool PopulateOnDemand {
265                         get {
266                                 object o = ViewState ["PopulateOnDemand"];
267                                 if (o != null)
268                                         return (bool)o;
269                                 return false;
270                         }
271                         set {
272                                 ViewState ["PopulateOnDemand"] = value;
273                                 if (value && nodes != null && nodes.Count > 0)
274                                         HadChildrenBeforePopulating = true;
275                                 else
276                                         HadChildrenBeforePopulating = false;
277                         }
278                 }
279
280                 [DefaultValue (TreeNodeSelectAction.Select)]
281                 public TreeNodeSelectAction SelectAction {
282                         get {
283                                 object o = ViewState ["SelectAction"];
284                                 if (o != null)
285                                         return (TreeNodeSelectAction)o;
286                                 return TreeNodeSelectAction.Select;
287                         }
288                         set { ViewState ["SelectAction"] = value; }
289                 }
290
291                 [DefaultValue (null)]
292                 public bool? ShowCheckBox {
293                         get {
294                                 object o = ViewState ["ShowCheckBox"];
295                                 return (bool?)o;
296                         }
297                         set { ViewState ["ShowCheckBox"] = value; }
298                 }
299
300                 internal bool ShowCheckBoxInternal {
301                         get {
302                                 if (ShowCheckBox.HasValue)
303                                         return ShowCheckBox.Value;
304                                 else
305                                         return (Tree.ShowCheckBoxes == TreeNodeTypes.All) ||
306                                                  ((Tree.ShowCheckBoxes & TreeNodeTypes.Leaf) > 0 && IsLeafNode) ||
307                                                  ((Tree.ShowCheckBoxes & TreeNodeTypes.Parent) > 0 && IsParentNode && Parent != null) ||
308                                                  ((Tree.ShowCheckBoxes & TreeNodeTypes.Root) > 0 && Parent == null && ChildNodes.Count > 0);
309                         }
310                 }
311                 
312                 [DefaultValue ("")]
313                 public string Target {
314                         get {
315                                 object o = ViewState ["Target"];
316                                 if(o != null)
317                                         return (string)o;
318                                 return String.Empty;
319                         }
320                         set { ViewState ["Target"] = value; }
321                 }
322
323                 [Localizable (true)]
324                 [DefaultValue ("")]
325                 [WebSysDescription ("The display text of the tree node.")]
326                 public string Text {
327                         get {
328                                 object o = ViewState ["Text"];
329                                 if (o == null)
330                                         o = ViewState ["Value"];
331                                 if (o != null)
332                                         return (string)o;
333                                 return String.Empty;
334                         }
335                         set { ViewState ["Text"] = value; }
336                 }
337
338                 [Localizable (true)]
339                 [DefaultValue ("")]
340                 public string ToolTip {
341                         get {
342                                 object o = ViewState ["ToolTip"];
343                                 if(o != null)
344                                         return (string)o;
345                                 return String.Empty;
346                         }
347                         set { ViewState ["ToolTip"] = value; }
348                 }
349
350                 [Localizable (true)]
351                 [DefaultValue ("")]
352                 public string Value {
353                         get {
354                                 object o = ViewState ["Value"];
355                                 if (o == null)
356                                         o = ViewState ["Text"];
357                                 if(o != null)
358                                         return (string)o;
359                                 return String.Empty;
360                         }
361                         set { ViewState ["Value"] = value; }
362                 }
363                 
364                 [DefaultValue (false)]
365                 public bool Selected {
366                         get { return SelectedFlag; }
367                         set {
368                                 SelectedFlag = value;
369                                 
370                                 if (tree != null) {
371                                         if (!value && tree.SelectedNode == this)
372                                                 tree.SetSelectedNode (null, false);
373                                         else if (value)
374                                                 tree.SetSelectedNode (this, false);
375                                 }
376                         }
377                 }
378                 
379                 internal virtual bool SelectedFlag {
380                         get {
381                                 object o = ViewState ["Selected"];
382                                 if(o != null)
383                                         return (bool)o;
384                                 return false;
385                         }
386                         set { ViewState ["Selected"] = value; }
387                 }
388                 
389                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
390                 [Browsable (false)]
391                 public TreeNode Parent {
392                         get { return parent; }
393                 }
394                 
395                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
396                 [Browsable (false)]
397                 public string ValuePath {
398                         get {
399                                 if (tree == null) return Value;
400                                 
401                                 StringBuilder sb = new StringBuilder (Value);
402                                 TreeNode node = parent;
403                                 while (node != null) {
404                                         sb.Insert (0, tree.PathSeparator);
405                                         sb.Insert (0, node.Value);
406                                         node = node.Parent;
407                                 }
408                                 return sb.ToString ();
409                         }
410                 }
411                 
412                 internal int Index {
413                         get { return index; }
414                         set { index = value; ResetPathData (); }
415                 }
416                 
417                 internal void SetParent (TreeNode node)
418                 {
419                         parent = node;
420                         ResetPathData ();
421                 }
422                 
423                 internal string Path {
424                         get {
425                                 if (path != null)
426                                         return path;
427                                 StringBuilder sb = new StringBuilder (index.ToString());
428                                 TreeNode node = parent;
429                                 while (node != null) {
430                                         sb.Insert (0, '_');
431                                         sb.Insert (0, node.Index.ToString ());
432                                         node = node.Parent;
433                                 }
434                                 path = sb.ToString ();
435                                 return path;
436                         }
437                 }
438                 
439                 internal bool Populated {
440                         get {
441                                 object o = ViewState ["Populated"];
442                                 if (o != null)
443                                         return (bool) o;
444                                 return false;
445                         }
446                         set { ViewState ["Populated"] = value; }
447                 }
448
449                 internal bool HasChildData {
450                         get { return nodes != null; }
451                 }
452                 
453                 internal void Populate ()
454                 {
455                         if (tree == null)
456                                 return;
457
458                         populating = true;
459                         tree.NotifyPopulateRequired (this);
460                         populating = false;
461                         Populated = true;
462                 }
463                 
464                 public void Collapse ()
465                 {
466                         Expanded = false;
467                 }
468
469                 public void CollapseAll ()
470                 {
471                         SetExpandedRec (false, -1);
472                 }
473
474                 public void Expand ()
475                 {
476                         Expanded = true;
477                 }
478
479                 internal void Expand (int depth)
480                 {
481                         SetExpandedRec (true, depth);
482                 }
483
484                 public void ExpandAll ()
485                 {
486                         SetExpandedRec (true, -1);
487                 }
488                 
489                 void SetExpandedRec (bool expanded, int depth)
490                 {
491                         Expanded = expanded;
492                         if (depth == 0)
493                                 return;
494                         
495                         foreach (TreeNode nod in ChildNodes)
496                                 nod.SetExpandedRec (expanded, depth - 1);
497                 }
498                 
499                 public void Select ()
500                 {
501                         Selected = true;
502                 }
503                 
504                 public void ToggleExpandState ()
505                 {
506                         Expanded = !Expanded.GetValueOrDefault(false);
507                 }
508
509                 void IStateManager.LoadViewState (object state)
510                 {
511                         LoadViewState (state);
512                 }
513
514                 protected virtual void LoadViewState (object state)
515                 {
516                         if (state == null)
517                                 return;
518
519                         object[] states = (object[]) state;
520                         ViewState.LoadViewState (states [0]);
521                         
522                         if (tree != null && SelectedFlag)
523                                 tree.SetSelectedNode (this, true);
524                         
525                         if (!PopulateOnDemand || Populated)
526                                 ((IStateManager)ChildNodes).LoadViewState (states [1]);
527                 }
528                 
529                 object IStateManager.SaveViewState ()
530                 {
531                         return SaveViewState ();
532                 }
533
534                 protected virtual object SaveViewState ()
535                 {
536                         object[] states = new object[2];
537                         states[0] = ViewState.SaveViewState();
538                         states[1] = (nodes == null ? null : ((IStateManager)nodes).SaveViewState());
539                         
540                         for (int i = 0; i < states.Length; i++) {
541                                 if (states [i] != null)
542                                         return states;
543                         }
544                         return null;
545                 }
546
547                 void IStateManager.TrackViewState ()
548                 {
549                         TrackViewState ();
550                 }
551
552                 protected void TrackViewState ()
553                 {
554                         if (marked) return;
555                         marked = true;
556                         ViewState.TrackViewState();
557
558                         if (nodes != null)
559                                 ((IStateManager)nodes).TrackViewState ();
560                 }
561                 
562                 bool IStateManager.IsTrackingViewState {
563                         get { return IsTrackingViewState; }
564                 }
565
566                 protected bool IsTrackingViewState {
567                         get { return marked; }
568                 }
569                 
570                 internal void SetDirty ()
571                 {
572                         ViewState.SetDirty (true);
573                         if (nodes != null)
574                                 nodes.SetDirty ();
575                 }
576                 
577                 public virtual object Clone ()
578                 {
579                         TreeNode nod = tree != null ? tree.CreateNode () : new TreeNode ();
580                         foreach (DictionaryEntry e in ViewState)
581                                 nod.ViewState [(string)e.Key] = ((StateItem)e.Value).Value;
582                                 
583                         foreach (TreeNode c in ChildNodes)
584                                 nod.ChildNodes.Add ((TreeNode)c.Clone ());
585                                 
586                         return nod;
587                 }
588
589                 object ICloneable.Clone ()
590                 {
591                         return Clone ();
592                 }
593                 
594                 internal void Bind (IHierarchyData hierarchyData)
595                 {
596                         this.hierarchyData = hierarchyData;
597                         DataBound = true;
598                         DataPath = hierarchyData.Path;
599                         dataItem = hierarchyData.Item;
600                         
601                         TreeNodeBinding bin = GetBinding ();
602                         if (bin != null) {
603                         
604                                 // Bind ImageToolTip property
605
606                                 if (bin.ImageToolTipField.Length > 0) {
607                                         ImageToolTip = Convert.ToString (GetBoundPropertyValue (bin.ImageToolTipField));
608                                         if (ImageToolTip.Length == 0)
609                                                 ImageToolTip = bin.ImageToolTip;
610                                 } else if (bin.ImageToolTip.Length > 0)
611                                         ImageToolTip = bin.ImageToolTip;
612                                         
613                                 // Bind ImageUrl property
614
615                                 if (bin.ImageUrlField.Length > 0) {
616                                         ImageUrl = Convert.ToString (GetBoundPropertyValue (bin.ImageUrlField));
617                                         if (ImageUrl.Length == 0)
618                                                 ImageUrl = bin.ImageUrl;
619                                 } else if (bin.ImageUrl.Length > 0)
620                                         ImageUrl = bin.ImageUrl;
621                                         
622                                 // Bind NavigateUrl property
623
624                                 if (bin.NavigateUrlField.Length > 0) {
625                                         NavigateUrl = Convert.ToString (GetBoundPropertyValue (bin.NavigateUrlField));
626                                         if (NavigateUrl.Length == 0)
627                                                 NavigateUrl = bin.NavigateUrl;
628                                 } else if (bin.NavigateUrl.Length > 0)
629                                         NavigateUrl = bin.NavigateUrl;
630                                         
631                                 // Bind PopulateOnDemand property
632                                 
633                                 if (bin.HasPropertyValue ("PopulateOnDemand"))
634                                         PopulateOnDemand = bin.PopulateOnDemand;
635                                 
636                                 // Bind SelectAction property
637                                         
638                                 if (bin.HasPropertyValue ("SelectAction"))
639                                         SelectAction = bin.SelectAction;
640                                 
641                                 // Bind ShowCheckBox property
642                                         
643                                 if (bin.HasPropertyValue ("ShowCheckBox"))
644                                         ShowCheckBox = bin.ShowCheckBox;
645                                         
646                                 // Bind Target property
647
648                                 if (bin.TargetField.Length > 0) {
649                                         Target = Convert.ToString (GetBoundPropertyValue (bin.TargetField));
650                                         if (Target.Length == 0)
651                                                 Target = bin.Target;
652                                 } else if (bin.Target.Length > 0)
653                                         Target = bin.Target;
654                                         
655                                 // Bind Text property
656                                 string text = null;
657                                 if (bin.TextField.Length > 0) {
658                                         text = Convert.ToString (GetBoundPropertyValue (bin.TextField));
659                                         if (bin.FormatString.Length > 0)
660                                                 text = string.Format (bin.FormatString, text);
661                                 }
662                                 if (String.IsNullOrEmpty (text)) {
663                                         if (bin.Text.Length > 0)
664                                                 text = bin.Text;
665                                         else if (bin.Value.Length > 0)
666                                                 text = bin.Value;
667                                 }
668                                 if (!String.IsNullOrEmpty (text))
669                                         Text = text;
670                                         
671                                 // Bind ToolTip property
672
673                                 if (bin.ToolTipField.Length > 0) {
674                                         ToolTip = Convert.ToString (GetBoundPropertyValue (bin.ToolTipField));
675                                         if (ToolTip.Length == 0)
676                                                 ToolTip = bin.ToolTip;
677                                 } else if (bin.ToolTip.Length > 0)
678                                         ToolTip = bin.ToolTip;
679                                         
680                                 // Bind Value property
681                                 string value = null;
682                                 if (bin.ValueField.Length > 0) {
683                                         value = Convert.ToString (GetBoundPropertyValue (bin.ValueField));
684                                 }
685                                 if (String.IsNullOrEmpty (value)) {
686                                         if (bin.Value.Length > 0)
687                                                 value = bin.Value;
688                                         else if (bin.Text.Length > 0)
689                                                 value = bin.Text;
690                                 }
691                                 if (!String.IsNullOrEmpty (value))
692                                         Value = value;
693                         } else {
694                                 Text = Value = GetDefaultBoundText ();
695                         }
696
697                         INavigateUIData navigateUIData = hierarchyData as INavigateUIData;
698                         if (navigateUIData != null) {
699                                 SelectAction = TreeNodeSelectAction.None;
700                                 Text = navigateUIData.ToString ();
701                                 NavigateUrl = navigateUIData.NavigateUrl;
702                                 ToolTip = navigateUIData.Description;
703                         }
704                 }
705                 
706                 internal void SetDataItem (object item)
707                 {
708                         dataItem = item;
709                 }
710                 
711                 internal void SetDataPath (string path)
712                 {
713                         DataPath = path;
714                 }
715                 
716                 internal void SetDataBound (bool bound)
717                 {
718                         DataBound = bound;
719                 }
720                 
721                 string GetDefaultBoundText ()
722                 {
723                         if (hierarchyData != null)
724                                 return hierarchyData.ToString ();
725                         else if (dataItem != null)
726                                 return dataItem.ToString ();
727                         else
728                                 return string.Empty;
729                 }
730                 
731                 string GetDataItemType ()
732                 {
733                         if (hierarchyData != null)
734                                 return hierarchyData.Type;
735                         else if (dataItem != null)
736                                 return dataItem.GetType().ToString ();
737                         else
738                                 return string.Empty;
739                 }
740                                 
741                 internal bool IsParentNode {
742                         get { return ChildNodes.Count > 0 || (PopulateOnDemand && !Populated); }
743                 }
744                 
745                 internal bool IsLeafNode {
746                         get { return !IsParentNode; }
747                 }
748                 
749                 internal bool IsRootNode {
750                         get { return Depth == 0; }
751                 }
752                 
753                 TreeNodeBinding GetBinding ()
754                 {
755                         if (tree == null)
756                                 return null;
757                         if (gotBinding)
758                                 return binding;
759                         binding = tree.FindBindingForNode (GetDataItemType (), Depth);
760                         gotBinding = true;
761                         return binding;
762                 }
763                 
764                 object GetBoundPropertyValue (string name)
765                 {
766                         if (boundProperties == null) {
767                                 if (hierarchyData != null)
768                                         boundProperties = TypeDescriptor.GetProperties (hierarchyData);
769                                 else
770                                         boundProperties = TypeDescriptor.GetProperties (dataItem);
771                         }
772                         
773                         PropertyDescriptor prop = boundProperties.Find (name, true);
774                         if (prop == null)
775                                 throw new InvalidOperationException ("Property '" + name + "' not found in data bound item");
776                                 
777                         if (hierarchyData != null)
778                                 return prop.GetValue (hierarchyData);
779                         else
780                                 return prop.GetValue (dataItem);
781                 }
782
783                 internal void BeginRenderText (HtmlTextWriter writer)
784                 {
785                         RenderPreText (writer);
786                 }
787                 
788                 internal void EndRenderText (HtmlTextWriter writer)
789                 {
790                         RenderPostText (writer);
791                 }
792                 
793                 protected virtual void RenderPreText (HtmlTextWriter writer)
794                 {
795                 }
796                 
797                 protected virtual void RenderPostText (HtmlTextWriter writer)
798                 {
799                 }
800         }
801 }