1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2004-2005 Novell, Inc.
23 // Jackson Harper (jackson@ximian.com)
24 // Kazuki Oikawa (kazuki@panicode.com)
27 using System.ComponentModel;
29 using System.Runtime.Serialization;
32 namespace System.Windows.Forms
34 [DefaultProperty ("Text")]
35 [TypeConverter(typeof(TreeNodeConverter))]
37 public class TreeNode : MarshalByRefObject, ICloneable, ISerializable
40 private TreeView tree_view;
41 internal TreeNode parent;
44 private int image_index = -1;
45 private int selected_image_index = -1;
46 private ContextMenu context_menu;
47 private ContextMenuStrip context_menu_strip;
48 private string image_key = String.Empty;
49 private string selected_image_key = String.Empty;
50 private int state_image_index = -1;
51 private string state_image_key = String.Empty;
52 private string tool_tip_text = String.Empty;
53 internal TreeNodeCollection nodes;
54 internal TreeViewAction check_reason = TreeViewAction.Unknown;
56 internal int visible_order = 0;
57 internal int width = -1;
59 internal bool is_expanded = false;
61 internal OwnerDrawPropertyBag prop_bag;
65 internal IntPtr handle;
67 private string name = string.Empty;
70 #region Internal Constructors
71 internal TreeNode (TreeView tree_view) : this ()
73 this.tree_view = tree_view;
77 protected TreeNode (SerializationInfo serializationInfo, StreamingContext context) : this ()
79 SerializationInfoEnumerator en;
83 en = serializationInfo.GetEnumerator();
85 while (en.MoveNext()) {
88 case "Text": Text = (string)e.Value; break;
89 case "PropBag": prop_bag = (OwnerDrawPropertyBag)e.Value; break;
90 case "ImageIndex": image_index = (int)e.Value; break;
91 case "SelectedImageIndex": selected_image_index = (int)e.Value; break;
92 case "Tag": tag = e.Value; break;
93 case "IsChecked": check = (bool)e.Value; break;
94 case "ChildCount": children = (int)e.Value; break;
98 for (int i = 0; i < children; i++) {
99 TreeNode node = (TreeNode) serializationInfo.GetValue ("children" + i, typeof (TreeNode));
104 #endregion // Internal Constructors
106 #region Public Constructors
109 nodes = new TreeNodeCollection (this);
112 public TreeNode (string text) : this ()
117 public TreeNode (string text, TreeNode [] children) : this (text)
119 Nodes.AddRange (children);
122 public TreeNode (string text, int imageIndex, int selectedImageIndex) : this (text)
124 this.image_index = imageIndex;
125 this.selected_image_index = selectedImageIndex;
128 public TreeNode (string text, int imageIndex, int selectedImageIndex,
130 : this (text, imageIndex, selectedImageIndex)
132 Nodes.AddRange (children);
135 #endregion // Public Constructors
137 #region ICloneable Members
138 public virtual object Clone ()
140 TreeNode tn = (TreeNode)Activator.CreateInstance (GetType ());
143 tn.image_key = image_key;
144 tn.image_index = image_index;
145 tn.selected_image_index = selected_image_index;
146 tn.selected_image_key = selected_image_key;
147 tn.state_image_index = state_image_index;
148 tn.state_image_key = state_image_key;
151 tn.tool_tip_text = tool_tip_text;
152 tn.context_menu = context_menu;
153 tn.context_menu_strip = context_menu_strip;
155 foreach (TreeNode child in nodes)
156 tn.nodes.Add ((TreeNode)child.Clone ());
158 if (prop_bag != null)
159 tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag);
163 #endregion // ICloneable Members
165 #region ISerializable Members
166 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context)
168 si.AddValue ("Text", Text);
169 si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag));
170 si.AddValue ("ImageIndex", ImageIndex);
171 si.AddValue ("SelectedImageIndex", SelectedImageIndex);
172 si.AddValue ("Tag", Tag);
173 si.AddValue ("Checked", Checked);
175 si.AddValue ("NumberOfChildren", Nodes.Count);
176 for (int i = 0; i < Nodes.Count; i++)
177 si.AddValue ("Child-" + i, Nodes [i], typeof (TreeNode));
180 protected virtual void Deserialize (SerializationInfo serializationInfo, StreamingContext context)
182 Text = serializationInfo.GetString ("Text");
183 prop_bag = (OwnerDrawPropertyBag)serializationInfo.GetValue ("prop_bag", typeof (OwnerDrawPropertyBag));
184 ImageIndex = serializationInfo.GetInt32 ("ImageIndex");
185 SelectedImageIndex = serializationInfo.GetInt32 ("SelectedImageIndex");
186 Tag = serializationInfo.GetValue ("Tag", typeof (Object));
187 Checked = serializationInfo.GetBoolean ("Checked");
189 int count = serializationInfo.GetInt32 ("NumberOfChildren");
191 for (int i = 0; i < count; i++)
192 Nodes.Add ((TreeNode)serializationInfo.GetValue ("Child-" + i, typeof (TreeNode)));
195 protected virtual void Serialize (SerializationInfo si, StreamingContext context)
197 si.AddValue ("Text", Text);
198 si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag));
199 si.AddValue ("ImageIndex", ImageIndex);
200 si.AddValue ("SelectedImageIndex", SelectedImageIndex);
201 si.AddValue ("Tag", Tag);
202 si.AddValue ("Checked", Checked);
204 si.AddValue ("NumberOfChildren", Nodes.Count);
205 for (int i = 0; i < Nodes.Count; i++)
206 si.AddValue ("Child-" + i, Nodes[i], typeof (TreeNode));
208 #endregion // ISerializable Members
210 #region Public Instance Properties
211 public Color BackColor {
213 if (prop_bag != null)
214 return prop_bag.BackColor;
218 if (prop_bag == null)
219 prop_bag = new OwnerDrawPropertyBag ();
220 prop_bag.BackColor = value;
222 TreeView tree_view = TreeView;
223 if (tree_view != null)
224 tree_view.UpdateNode (this);
229 public Rectangle Bounds {
231 if (TreeView == null)
232 return Rectangle.Empty;
238 width = TreeView.GetNodeWidth (this);
240 Rectangle res = new Rectangle (x, y, width, TreeView.ActualItemHeight);
247 if (TreeView == null)
249 return (visible_order - 1) * TreeView.ActualItemHeight - (TreeView.skipped_nodes * TreeView.ActualItemHeight);
254 if (TreeView == null)
256 int indent_level = IndentLevel;
257 int roots = (TreeView.ShowRootLines ? 1 : 0);
258 int cb = (TreeView.CheckBoxes ? 19 : 0);
259 if (!TreeView.CheckBoxes && StateImage != null)
261 int imgs = (TreeView.ImageList != null ? TreeView.ImageList.ImageSize.Width + 3 : 0);
262 return ((indent_level + roots) * TreeView.Indent) + cb + imgs - TreeView.hbar_offset;
265 internal int GetLinesX ()
267 int roots = (TreeView.ShowRootLines ? 1 : 0);
268 return (IndentLevel + roots) * TreeView.Indent - TreeView.hbar_offset;
271 internal int GetImageX ()
273 return GetLinesX () + (TreeView.CheckBoxes || StateImage != null ? 19 : 0);
276 // In theory we should be able to track this instead of computing
277 // every single time we need it, however for now I am going to
278 // do it this way to reduce bugs in my new bounds computing code
279 internal int IndentLevel {
281 TreeNode walk = this;
283 while (walk.Parent != null) {
292 [DefaultValue (false)]
293 public bool Checked {
294 get { return check; }
298 TreeViewCancelEventArgs args = new TreeViewCancelEventArgs (this, false, check_reason);
299 if (TreeView != null)
300 TreeView.OnBeforeCheck (args);
304 // TreeView can become null after OnAfterCheck, this the double null check
305 if (TreeView != null)
306 TreeView.OnAfterCheck (new TreeViewEventArgs (this, check_reason));
307 if (TreeView != null)
308 TreeView.UpdateNode (this);
310 check_reason = TreeViewAction.Unknown;
314 [DefaultValue (null)]
315 public virtual ContextMenu ContextMenu {
316 get { return context_menu; }
317 set { context_menu = value; }
320 [DefaultValue (null)]
321 public virtual ContextMenuStrip ContextMenuStrip {
322 get { return context_menu_strip; }
323 set { context_menu_strip = value; }
327 public TreeNode FirstNode {
335 public Color ForeColor {
337 if (prop_bag != null)
338 return prop_bag.ForeColor;
339 if (TreeView != null)
340 return TreeView.ForeColor;
344 if (prop_bag == null)
345 prop_bag = new OwnerDrawPropertyBag ();
346 prop_bag.ForeColor = value;
348 TreeView tree_view = TreeView;
349 if (tree_view != null)
350 tree_view.UpdateNode (this);
355 public string FullPath {
357 if (TreeView == null)
358 throw new InvalidOperationException ("No TreeView associated");
360 StringBuilder builder = new StringBuilder ();
361 BuildFullPath (builder);
362 return builder.ToString ();
367 [RelatedImageList ("TreeView.ImageList")]
368 [TypeConverter (typeof (TreeViewImageIndexConverter))]
369 [RefreshProperties (RefreshProperties.Repaint)]
370 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
372 public int ImageIndex {
373 get { return image_index; }
375 if (image_index == value)
378 image_key = string.Empty;
379 TreeView tree = TreeView;
381 tree.UpdateNode (this);
387 [RelatedImageList ("TreeView.ImageList")]
388 [TypeConverter (typeof (TreeViewImageKeyConverter))]
389 [RefreshProperties (RefreshProperties.Repaint)]
390 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
391 public string ImageKey {
392 get { return image_key; }
394 if (image_key == value)
399 TreeView tree = TreeView;
401 tree.UpdateNode(this);
406 public bool IsEditing {
408 TreeView tv = TreeView;
411 return tv.edit_node == this;
416 public bool IsExpanded {
418 TreeView tv = TreeView;
420 if (tv != null && tv.IsHandleCreated) {
421 // This is ridiculous
423 foreach (TreeNode walk in TreeView.Nodes) {
424 if (walk.Nodes.Count > 0)
437 public bool IsSelected {
439 if (TreeView == null || !TreeView.IsHandleCreated)
441 return TreeView.SelectedNode == this;
446 public bool IsVisible {
448 if (TreeView == null || !TreeView.IsHandleCreated || !TreeView.Visible)
451 if (visible_order <= TreeView.skipped_nodes || visible_order - TreeView.skipped_nodes > TreeView.VisibleCount)
454 return ArePreviousNodesExpanded;
459 public TreeNode LastNode {
461 return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1];
467 get { return IndentLevel; }
472 get { return this.name; }
474 // Value should never be null as per spec
475 this.name = (value == null) ? string.Empty : value;
480 public TreeNode NextNode {
485 if (parent.Nodes.Count > index + 1)
486 return parent.Nodes [index + 1];
492 public TreeNode NextVisibleNode {
494 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
495 o.MoveNext (); // move to the node itself
499 TreeNode c = o.CurrentNode;
500 if (!c.IsInClippingRect)
506 [DefaultValue (null)]
508 public Font NodeFont {
510 if (prop_bag != null)
511 return prop_bag.Font;
512 if (TreeView != null)
513 return TreeView.Font;
517 if (prop_bag == null)
518 prop_bag = new OwnerDrawPropertyBag ();
519 prop_bag.Font = value;
525 [ListBindable (false)]
526 public TreeNodeCollection Nodes {
529 nodes = new TreeNodeCollection (this);
535 public TreeNode Parent {
537 TreeView tree_view = TreeView;
538 if (tree_view != null && tree_view.root_node == parent)
545 public TreeNode PrevNode {
550 if (index <= 0 || index > parent.Nodes.Count)
552 return parent.Nodes [index - 1];
557 public TreeNode PrevVisibleNode {
559 OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this);
560 o.MovePrevious (); // move to the node itself
562 if (!o.MovePrevious ())
564 TreeNode c = o.CurrentNode;
565 if (!c.IsInClippingRect)
572 [RelatedImageList ("TreeView.ImageList")]
573 [TypeConverter (typeof (TreeViewImageIndexConverter))]
574 [RefreshProperties (RefreshProperties.Repaint)]
575 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
577 public int SelectedImageIndex {
578 get { return selected_image_index; }
579 set { selected_image_index = value; }
584 [RelatedImageList ("TreeView.ImageList")]
585 [TypeConverter (typeof (TreeViewImageKeyConverter))]
586 [RefreshProperties (RefreshProperties.Repaint)]
587 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
588 public string SelectedImageKey {
589 get { return selected_image_key; }
590 set { selected_image_key = value; }
595 [RelatedImageList ("TreeView.StateImageList")]
596 [TypeConverter (typeof (NoneExcludedImageIndexConverter))]
597 [RefreshProperties (RefreshProperties.Repaint)]
598 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
599 public int StateImageIndex {
600 get { return state_image_index; }
602 if (state_image_index != value) {
603 state_image_index = value;
604 state_image_key = string.Empty;
612 [RelatedImageList ("TreeView.StateImageList")]
613 [TypeConverter (typeof (ImageKeyConverter))]
614 [RefreshProperties (RefreshProperties.Repaint)]
615 [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
616 public string StateImageKey {
617 get { return state_image_key; }
619 if (state_image_key != value) {
620 state_image_key = value;
621 state_image_index = -1;
629 [TypeConverter(typeof(System.ComponentModel.StringConverter))]
648 // UIA Framework Event: Text Changed
649 TreeView view = TreeView;
651 view.OnUIANodeTextChanged (new TreeViewEventArgs (this));
656 [Localizable (false)]
657 public string ToolTipText {
658 get { return tool_tip_text; }
659 set { tool_tip_text = value; }
663 public TreeView TreeView {
665 if (tree_view != null)
667 TreeNode walk = parent;
668 while (walk != null) {
669 if (walk.TreeView != null)
675 return walk.TreeView;
680 public IntPtr Handle {
682 // MS throws a NullReferenceException if the TreeView isn't set...
683 if (handle == IntPtr.Zero && TreeView != null)
684 handle = TreeView.CreateNodeHandle ();
689 #endregion // Public Instance Properties
692 public static TreeNode FromHandle (TreeView tree, IntPtr handle)
694 if (handle == IntPtr.Zero)
696 // No arg checking on MS it just throws a NullRef if treeview is null
697 return tree.NodeFromHandle (handle);
700 #region Public Instance Methods
701 public void BeginEdit ()
703 TreeView tv = TreeView;
708 public void Collapse ()
710 CollapseInternal (false);
713 public void Collapse (bool ignoreChildren)
718 CollapseRecursive (this);
721 public void EndEdit (bool cancel)
723 TreeView tv = TreeView;
724 if (!cancel && tv != null)
726 else if (cancel && tv != null)
727 tv.CancelEdit (this);
730 public void Expand ()
735 public void ExpandAll ()
737 ExpandRecursive (this);
739 TreeView.UpdateNode (TreeView.root_node);
742 public void EnsureVisible ()
744 if (TreeView == null)
747 if (this.Parent != null)
748 ExpandParentRecursive (this.Parent);
750 Rectangle bounds = Bounds;
752 TreeView.SetTop (this);
753 } else if (bounds.Bottom > TreeView.ViewportRectangle.Bottom) {
754 TreeView.SetBottom (this);
758 public int GetNodeCount (bool includeSubTrees)
760 if (!includeSubTrees)
764 GetNodeCountRecursive (this, ref count);
769 public void Remove ()
774 parent.Nodes.RemoveAt (index);
777 public void Toggle ()
785 public override String ToString ()
787 return String.Concat ("TreeNode: ", Text);
790 #endregion // Public Instance Methods
792 #region Internal & Private Methods and Properties
794 internal bool ArePreviousNodesExpanded {
796 TreeNode parent = Parent;
797 while (parent != null) {
798 if (!parent.is_expanded)
800 parent = parent.Parent;
807 internal bool IsRoot {
809 TreeView tree_view = TreeView;
810 if (tree_view == null)
812 if (tree_view.root_node == this)
818 bool BuildFullPath (StringBuilder path)
823 if (parent.BuildFullPath (path))
824 path.Append (TreeView.PathSeparator);
834 return parent.Nodes.IndexOf (this);
838 private void Expand (bool byInternal)
840 if (is_expanded || nodes.Count < 1) {
846 TreeView tree_view = TreeView;
847 if (tree_view != null) {
848 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand);
849 tree_view.OnBeforeExpand (e);
855 int count_to_next = CountToNext ();
857 if (tree_view != null) {
858 tree_view.OnAfterExpand (new TreeViewEventArgs (this));
860 tree_view.RecalculateVisibleOrder (this);
861 tree_view.UpdateScrollBars (false);
863 // ExpandBelow if we affect the visible area
864 if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded)
865 tree_view.ExpandBelow (this, count_to_next);
870 private void CollapseInternal (bool byInternal)
872 if (!is_expanded || nodes.Count < 1)
879 TreeView tree_view = TreeView;
880 if (tree_view != null) {
881 TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse);
882 tree_view.OnBeforeCollapse (e);
887 int count_to_next = CountToNext ();
891 if (tree_view != null) {
892 tree_view.OnAfterCollapse (new TreeViewEventArgs (this));
894 bool hbar_visible = tree_view.hbar.Visible;
895 bool vbar_visible = tree_view.vbar.Visible;
897 tree_view.RecalculateVisibleOrder (this);
898 tree_view.UpdateScrollBars (false);
900 // CollapseBelow if we affect the visible area
901 if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded)
902 tree_view.CollapseBelow (this, count_to_next);
903 if(!byInternal && HasFocusInChildren ())
904 tree_view.SelectedNode = this;
906 // If one or both of our scrollbars disappeared,
907 // invalidate everything
908 if ((hbar_visible & !tree_view.hbar.Visible) || (vbar_visible & !tree_view.vbar.Visible))
909 tree_view.Invalidate ();
914 private int CountToNext ()
916 bool expanded = is_expanded;
918 OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (this);
921 if (walk.MoveNext () && walk.MoveNext ())
922 next = walk.CurrentNode;
924 is_expanded = expanded;
929 while (walk.MoveNext () && walk.CurrentNode != next)
935 private bool HasFocusInChildren()
937 if (TreeView == null)
939 foreach (TreeNode node in nodes) {
940 if(node == TreeView.SelectedNode)
942 if(node.HasFocusInChildren ())
948 private void ExpandRecursive (TreeNode node)
951 foreach (TreeNode child in node.Nodes)
952 ExpandRecursive (child);
955 private void ExpandParentRecursive (TreeNode node)
958 if (node.Parent != null)
959 ExpandParentRecursive (node.Parent);
962 internal void CollapseAll ()
964 CollapseRecursive (this);
967 internal void CollapseAllUncheck ()
969 CollapseUncheckRecursive (this);
972 private void CollapseRecursive (TreeNode node)
975 foreach (TreeNode child in node.Nodes)
976 CollapseRecursive (child);
979 private void CollapseUncheckRecursive (TreeNode node)
982 node.Checked = false;
983 foreach (TreeNode child in node.Nodes)
984 CollapseUncheckRecursive (child);
987 internal void SetNodes (TreeNodeCollection nodes)
992 private void GetNodeCountRecursive (TreeNode node, ref int count)
994 count += node.Nodes.Count;
995 foreach (TreeNode child in node.Nodes)
996 GetNodeCountRecursive (child, ref count);
999 internal bool NeedsWidth {
1000 get { return width == -1; }
1003 internal void Invalidate ()
1005 // invalidate width first so Bounds retrieves
1006 // the updated value (we don't use it here however)
1009 TreeView tv = TreeView;
1013 tv.UpdateNode (this);
1016 internal void InvalidateWidth ()
1018 // bounds.Width = 0;
1022 internal void SetWidth (int width)
1027 internal void SetParent (TreeNode parent)
1029 this.parent = parent;
1032 private bool IsInClippingRect {
1034 if (TreeView == null)
1036 Rectangle bounds = Bounds;
1037 if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height)
1043 internal Image StateImage {
1045 if (TreeView != null) {
1046 if (TreeView.StateImageList == null)
1048 if (state_image_index >= 0)
1049 return TreeView.StateImageList.Images[state_image_index];
1050 if (state_image_key != string.Empty)
1051 return TreeView.StateImageList.Images[state_image_key];
1058 // Order of operation:
1059 // 1) Node.Image[Key|Index]
1060 // 2) TreeView.Image[Key|Index]
1061 // 3) First image in TreeView.ImageList
1062 internal int Image {
1064 if (TreeView == null || TreeView.ImageList == null)
1068 if (selected_image_index >= 0)
1069 return selected_image_index;
1070 if (!string.IsNullOrEmpty (selected_image_key))
1071 return TreeView.ImageList.Images.IndexOfKey (selected_image_key);
1072 if (!string.IsNullOrEmpty (TreeView.SelectedImageKey))
1073 return TreeView.ImageList.Images.IndexOfKey (TreeView.SelectedImageKey);
1074 if (TreeView.SelectedImageIndex >= 0)
1075 return TreeView.SelectedImageIndex;
1077 if (image_index >= 0)
1079 if (!string.IsNullOrEmpty (image_key))
1080 return TreeView.ImageList.Images.IndexOfKey (image_key);
1081 if (!string.IsNullOrEmpty (TreeView.ImageKey))
1082 return TreeView.ImageList.Images.IndexOfKey (TreeView.ImageKey);
1083 if (TreeView.ImageIndex >= 0)
1084 return TreeView.ImageIndex;
1087 if (TreeView.ImageList.Images.Count > 0)
1093 #endregion // Internal & Private Methods and Properties