// Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Copyright (c) 2004-2005 Novell, Inc. // // Authors: // Jackson Harper (jackson@ximian.com) // Kazuki Oikawa (kazuki@panicode.com) using System; using System.ComponentModel; using System.Drawing; using System.Runtime.Serialization; using System.Text; namespace System.Windows.Forms { [DefaultProperty ("Text")] [TypeConverter(typeof(TreeNodeConverter))] [Serializable] public class TreeNode : MarshalByRefObject, ICloneable, ISerializable { #region Fields private TreeView tree_view; internal TreeNode parent; private string text; private int image_index = -1; private int selected_image_index = -1; private ContextMenu context_menu; private ContextMenuStrip context_menu_strip; private string image_key = String.Empty; private string selected_image_key = String.Empty; private int state_image_index = -1; private string state_image_key = String.Empty; private string tool_tip_text = String.Empty; internal TreeNodeCollection nodes; internal TreeViewAction check_reason = TreeViewAction.Unknown; internal int visible_order = 0; internal int width = -1; internal bool is_expanded = false; private bool check; internal OwnerDrawPropertyBag prop_bag; private object tag; internal IntPtr handle; private string name = string.Empty; #endregion // Fields #region Internal Constructors internal TreeNode (TreeView tree_view) : this () { this.tree_view = tree_view; is_expanded = true; } protected TreeNode (SerializationInfo serializationInfo, StreamingContext context) : this () { SerializationInfoEnumerator en; SerializationEntry e; int children; en = serializationInfo.GetEnumerator(); children = 0; while (en.MoveNext()) { e = en.Current; switch(e.Name) { case "Text": Text = (string)e.Value; break; case "PropBag": prop_bag = (OwnerDrawPropertyBag)e.Value; break; case "ImageIndex": image_index = (int)e.Value; break; case "SelectedImageIndex": selected_image_index = (int)e.Value; break; case "Tag": tag = e.Value; break; case "IsChecked": check = (bool)e.Value; break; case "ChildCount": children = (int)e.Value; break; } } if (children > 0) { for (int i = 0; i < children; i++) { TreeNode node = (TreeNode) serializationInfo.GetValue ("children" + i, typeof (TreeNode)); Nodes.Add (node); } } } #endregion // Internal Constructors #region Public Constructors public TreeNode () { nodes = new TreeNodeCollection (this); } public TreeNode (string text) : this () { Text = text; } public TreeNode (string text, TreeNode [] children) : this (text) { Nodes.AddRange (children); } public TreeNode (string text, int imageIndex, int selectedImageIndex) : this (text) { this.image_index = imageIndex; this.selected_image_index = selectedImageIndex; } public TreeNode (string text, int imageIndex, int selectedImageIndex, TreeNode[] children) : this (text, imageIndex, selectedImageIndex) { Nodes.AddRange (children); } #endregion // Public Constructors #region ICloneable Members public virtual object Clone () { TreeNode tn = (TreeNode)Activator.CreateInstance (GetType ()); tn.name = name; tn.text = text; tn.image_key = image_key; tn.image_index = image_index; tn.selected_image_index = selected_image_index; tn.selected_image_key = selected_image_key; tn.state_image_index = state_image_index; tn.state_image_key = state_image_key; tn.tag = tag; tn.check = check; tn.tool_tip_text = tool_tip_text; tn.context_menu = context_menu; tn.context_menu_strip = context_menu_strip; if (nodes != null) { foreach (TreeNode child in nodes) tn.nodes.Add ((TreeNode)child.Clone ()); } if (prop_bag != null) tn.prop_bag = OwnerDrawPropertyBag.Copy (prop_bag); return tn; } #endregion // ICloneable Members #region ISerializable Members void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context) { si.AddValue ("Text", Text); si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag)); si.AddValue ("ImageIndex", ImageIndex); si.AddValue ("SelectedImageIndex", SelectedImageIndex); si.AddValue ("Tag", Tag); si.AddValue ("Checked", Checked); si.AddValue ("NumberOfChildren", Nodes.Count); for (int i = 0; i < Nodes.Count; i++) si.AddValue ("Child-" + i, Nodes [i], typeof (TreeNode)); } protected virtual void Deserialize (SerializationInfo serializationInfo, StreamingContext context) { Text = serializationInfo.GetString ("Text"); prop_bag = (OwnerDrawPropertyBag)serializationInfo.GetValue ("prop_bag", typeof (OwnerDrawPropertyBag)); ImageIndex = serializationInfo.GetInt32 ("ImageIndex"); SelectedImageIndex = serializationInfo.GetInt32 ("SelectedImageIndex"); Tag = serializationInfo.GetValue ("Tag", typeof (Object)); Checked = serializationInfo.GetBoolean ("Checked"); int count = serializationInfo.GetInt32 ("NumberOfChildren"); for (int i = 0; i < count; i++) Nodes.Add ((TreeNode)serializationInfo.GetValue ("Child-" + i, typeof (TreeNode))); } protected virtual void Serialize (SerializationInfo si, StreamingContext context) { si.AddValue ("Text", Text); si.AddValue ("prop_bag", prop_bag, typeof (OwnerDrawPropertyBag)); si.AddValue ("ImageIndex", ImageIndex); si.AddValue ("SelectedImageIndex", SelectedImageIndex); si.AddValue ("Tag", Tag); si.AddValue ("Checked", Checked); si.AddValue ("NumberOfChildren", Nodes.Count); for (int i = 0; i < Nodes.Count; i++) si.AddValue ("Child-" + i, Nodes[i], typeof (TreeNode)); } #endregion // ISerializable Members #region Public Instance Properties public Color BackColor { get { if (prop_bag != null) return prop_bag.BackColor; return Color.Empty; } set { if (prop_bag == null) prop_bag = new OwnerDrawPropertyBag (); prop_bag.BackColor = value; TreeView tree_view = TreeView; if (tree_view != null) tree_view.UpdateNode (this); } } [Browsable (false)] public Rectangle Bounds { get { if (TreeView == null) return Rectangle.Empty; int x = GetX (); int y = GetY (); if (width == -1) width = TreeView.GetNodeWidth (this); Rectangle res = new Rectangle (x, y, width, TreeView.ActualItemHeight); return res; } } internal int GetY () { if (TreeView == null) return 0; return (visible_order - 1) * TreeView.ActualItemHeight - (TreeView.skipped_nodes * TreeView.ActualItemHeight); } internal int GetX () { if (TreeView == null) return 0; int indent_level = IndentLevel; int roots = (TreeView.ShowRootLines ? 1 : 0); int cb = (TreeView.CheckBoxes ? 19 : 0); if (!TreeView.CheckBoxes && StateImage != null) cb = 19; int imgs = (TreeView.ImageList != null ? TreeView.ImageList.ImageSize.Width + 3 : 0); return ((indent_level + roots) * TreeView.Indent) + cb + imgs - TreeView.hbar_offset; } internal int GetLinesX () { int roots = (TreeView.ShowRootLines ? 1 : 0); return (IndentLevel + roots) * TreeView.Indent - TreeView.hbar_offset; } internal int GetImageX () { return GetLinesX () + (TreeView.CheckBoxes || StateImage != null ? 19 : 0); } // In theory we should be able to track this instead of computing // every single time we need it, however for now I am going to // do it this way to reduce bugs in my new bounds computing code internal int IndentLevel { get { TreeNode walk = this; int res = 0; while (walk.Parent != null) { walk = walk.Parent; res++; } return res; } } [DefaultValue (false)] public bool Checked { get { return check; } set { if (check == value) return; TreeViewCancelEventArgs args = new TreeViewCancelEventArgs (this, false, check_reason); if (TreeView != null) TreeView.OnBeforeCheck (args); if (!args.Cancel) { check = value; // TreeView can become null after OnAfterCheck, this the double null check if (TreeView != null) TreeView.OnAfterCheck (new TreeViewEventArgs (this, check_reason)); if (TreeView != null) TreeView.UpdateNode (this); } check_reason = TreeViewAction.Unknown; } } [DefaultValue (null)] public virtual ContextMenu ContextMenu { get { return context_menu; } set { context_menu = value; } } [DefaultValue (null)] public virtual ContextMenuStrip ContextMenuStrip { get { return context_menu_strip; } set { context_menu_strip = value; } } [Browsable (false)] public TreeNode FirstNode { get { if (nodes.Count > 0) return nodes [0]; return null; } } public Color ForeColor { get { if (prop_bag != null) return prop_bag.ForeColor; if (TreeView != null) return TreeView.ForeColor; return Color.Empty; } set { if (prop_bag == null) prop_bag = new OwnerDrawPropertyBag (); prop_bag.ForeColor = value; TreeView tree_view = TreeView; if (tree_view != null) tree_view.UpdateNode (this); } } [Browsable (false)] public string FullPath { get { if (TreeView == null) throw new InvalidOperationException ("No TreeView associated"); StringBuilder builder = new StringBuilder (); BuildFullPath (builder); return builder.ToString (); } } [DefaultValue (-1)] [RelatedImageList ("TreeView.ImageList")] [TypeConverter (typeof (TreeViewImageIndexConverter))] [RefreshProperties (RefreshProperties.Repaint)] [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] [Localizable(true)] public int ImageIndex { get { return image_index; } set { if (image_index == value) return; image_index = value; image_key = string.Empty; TreeView tree = TreeView; if (tree != null) tree.UpdateNode (this); } } [Localizable(true)] [DefaultValue ("")] [RelatedImageList ("TreeView.ImageList")] [TypeConverter (typeof (TreeViewImageKeyConverter))] [RefreshProperties (RefreshProperties.Repaint)] [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] public string ImageKey { get { return image_key; } set { if (image_key == value) return; image_key = value; image_index = -1; TreeView tree = TreeView; if (tree != null) tree.UpdateNode(this); } } [Browsable (false)] public bool IsEditing { get { TreeView tv = TreeView; if (tv == null) return false; return tv.edit_node == this; } } [Browsable (false)] public bool IsExpanded { get { TreeView tv = TreeView; if (tv != null && tv.IsHandleCreated) { // This is ridiculous bool found = false; foreach (TreeNode walk in TreeView.Nodes) { if (walk.Nodes.Count > 0) found = true; } if (!found) return false; } return is_expanded; } } [Browsable (false)] public bool IsSelected { get { if (TreeView == null || !TreeView.IsHandleCreated) return false; return TreeView.SelectedNode == this; } } [Browsable (false)] public bool IsVisible { get { if (TreeView == null || !TreeView.IsHandleCreated || !TreeView.Visible) return false; if (visible_order <= TreeView.skipped_nodes || visible_order - TreeView.skipped_nodes > TreeView.VisibleCount) return false; return ArePreviousNodesExpanded; } } [Browsable (false)] public TreeNode LastNode { get { return (nodes == null || nodes.Count == 0) ? null : nodes [nodes.Count - 1]; } } [Browsable (false)] public int Level { get { return IndentLevel; } } public string Name { get { return this.name; } set { // Value should never be null as per spec this.name = (value == null) ? string.Empty : value; } } [Browsable (false)] public TreeNode NextNode { get { if (parent == null) return null; int index = Index; if (parent.Nodes.Count > index + 1) return parent.Nodes [index + 1]; return null; } } [Browsable (false)] public TreeNode NextVisibleNode { get { OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this); o.MoveNext (); // move to the node itself if (!o.MoveNext ()) return null; TreeNode c = o.CurrentNode; if (!c.IsInClippingRect) return null; return c; } } [DefaultValue (null)] [Localizable (true)] public Font NodeFont { get { if (prop_bag != null) return prop_bag.Font; if (TreeView != null) return TreeView.Font; return null; } set { if (prop_bag == null) prop_bag = new OwnerDrawPropertyBag (); prop_bag.Font = value; Invalidate (); } } [Browsable (false)] [ListBindable (false)] public TreeNodeCollection Nodes { get { if (nodes == null) nodes = new TreeNodeCollection (this); return nodes; } } [Browsable (false)] public TreeNode Parent { get { TreeView tree_view = TreeView; if (tree_view != null && tree_view.root_node == parent) return null; return parent; } } [Browsable (false)] public TreeNode PrevNode { get { if (parent == null) return null; int index = Index; if (index <= 0 || index > parent.Nodes.Count) return null; return parent.Nodes [index - 1]; } } [Browsable (false)] public TreeNode PrevVisibleNode { get { OpenTreeNodeEnumerator o = new OpenTreeNodeEnumerator (this); o.MovePrevious (); // move to the node itself if (!o.MovePrevious ()) return null; TreeNode c = o.CurrentNode; if (!c.IsInClippingRect) return null; return c; } } [DefaultValue (-1)] [RelatedImageList ("TreeView.ImageList")] [TypeConverter (typeof (TreeViewImageIndexConverter))] [RefreshProperties (RefreshProperties.Repaint)] [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] [Localizable (true)] public int SelectedImageIndex { get { return selected_image_index; } set { selected_image_index = value; } } [Localizable (true)] [DefaultValue ("")] [RelatedImageList ("TreeView.ImageList")] [TypeConverter (typeof (TreeViewImageKeyConverter))] [RefreshProperties (RefreshProperties.Repaint)] [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] public string SelectedImageKey { get { return selected_image_key; } set { selected_image_key = value; } } [Localizable (true)] [DefaultValue (-1)] [RelatedImageList ("TreeView.StateImageList")] [TypeConverter (typeof (NoneExcludedImageIndexConverter))] [RefreshProperties (RefreshProperties.Repaint)] [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] public int StateImageIndex { get { return state_image_index; } set { if (state_image_index != value) { state_image_index = value; state_image_key = string.Empty; Invalidate (); } } } [Localizable (true)] [DefaultValue ("")] [RelatedImageList ("TreeView.StateImageList")] [TypeConverter (typeof (ImageKeyConverter))] [RefreshProperties (RefreshProperties.Repaint)] [Editor ("System.Windows.Forms.Design.ImageIndexEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] public string StateImageKey { get { return state_image_key; } set { if (state_image_key != value) { state_image_key = value; state_image_index = -1; Invalidate (); } } } [Bindable(true)] [Localizable(false)] [TypeConverter(typeof(System.ComponentModel.StringConverter))] [DefaultValue(null)] public object Tag { get { return tag; } set { tag = value; } } [Localizable(true)] public string Text { get { if (text == null) return String.Empty; return text; } set { if (text == value) return; text = value; Invalidate (); // UIA Framework Event: Text Changed TreeView view = TreeView; if (view != null) view.OnUIANodeTextChanged (new TreeViewEventArgs (this)); } } [DefaultValue ("")] [Localizable (false)] public string ToolTipText { get { return tool_tip_text; } set { tool_tip_text = value; } } [Browsable (false)] public TreeView TreeView { get { if (tree_view != null) return tree_view; TreeNode walk = parent; while (walk != null) { if (walk.TreeView != null) break; walk = walk.parent; } if (walk == null) return null; return walk.TreeView; } } [Browsable (false)] public IntPtr Handle { get { // MS throws a NullReferenceException if the TreeView isn't set... if (handle == IntPtr.Zero && TreeView != null) handle = TreeView.CreateNodeHandle (); return handle; } } #endregion // Public Instance Properties public static TreeNode FromHandle (TreeView tree, IntPtr handle) { if (handle == IntPtr.Zero) return null; // No arg checking on MS it just throws a NullRef if treeview is null return tree.NodeFromHandle (handle); } #region Public Instance Methods public void BeginEdit () { TreeView tv = TreeView; if (tv != null) tv.BeginEdit (this); } public void Collapse () { CollapseInternal (false); } public void Collapse (bool ignoreChildren) { if (ignoreChildren) Collapse (); else CollapseRecursive (this); } public void EndEdit (bool cancel) { TreeView tv = TreeView; if (!cancel && tv != null) tv.EndEdit (this); else if (cancel && tv != null) tv.CancelEdit (this); } public void Expand () { Expand (false); } public void ExpandAll () { ExpandRecursive (this); if(TreeView != null) TreeView.UpdateNode (TreeView.root_node); } public void EnsureVisible () { if (TreeView == null) return; if (this.Parent != null) ExpandParentRecursive (this.Parent); Rectangle bounds = Bounds; if (bounds.Y < 0) { TreeView.SetTop (this); } else if (bounds.Bottom > TreeView.ViewportRectangle.Bottom) { TreeView.SetBottom (this); } } public int GetNodeCount (bool includeSubTrees) { if (!includeSubTrees) return Nodes.Count; int count = 0; GetNodeCountRecursive (this, ref count); return count; } public void Remove () { if (parent == null) return; int index = Index; parent.Nodes.RemoveAt (index); } public void Toggle () { if (is_expanded) Collapse (); else Expand (); } public override String ToString () { return String.Concat ("TreeNode: ", Text); } #endregion // Public Instance Methods #region Internal & Private Methods and Properties internal bool ArePreviousNodesExpanded { get { TreeNode parent = Parent; while (parent != null) { if (!parent.is_expanded) return false; parent = parent.Parent; } return true; } } internal bool IsRoot { get { TreeView tree_view = TreeView; if (tree_view == null) return false; if (tree_view.root_node == this) return true; return false; } } bool BuildFullPath (StringBuilder path) { if (parent == null) return false; if (parent.BuildFullPath (path)) path.Append (TreeView.PathSeparator); path.Append (text); return true; } public int Index { get { if (parent == null) return 0; return parent.Nodes.IndexOf (this); } } private void Expand (bool byInternal) { if (is_expanded || nodes.Count < 1) { is_expanded = true; return; } bool cancel = false; TreeView tree_view = TreeView; if (tree_view != null) { TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Expand); tree_view.OnBeforeExpand (e); cancel = e.Cancel; } if (!cancel) { is_expanded = true; int count_to_next = CountToNext (); if (tree_view != null) { tree_view.OnAfterExpand (new TreeViewEventArgs (this)); tree_view.RecalculateVisibleOrder (this); tree_view.UpdateScrollBars (false); // ExpandBelow if we affect the visible area if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded) tree_view.ExpandBelow (this, count_to_next); } } } private void CollapseInternal (bool byInternal) { if (!is_expanded || nodes.Count < 1) return; if (IsRoot) return; bool cancel = false; TreeView tree_view = TreeView; if (tree_view != null) { TreeViewCancelEventArgs e = new TreeViewCancelEventArgs (this, false, TreeViewAction.Collapse); tree_view.OnBeforeCollapse (e); cancel = e.Cancel; } if (!cancel) { int count_to_next = CountToNext (); is_expanded = false; if (tree_view != null) { tree_view.OnAfterCollapse (new TreeViewEventArgs (this)); bool hbar_visible = tree_view.hbar.Visible; bool vbar_visible = tree_view.vbar.Visible; tree_view.RecalculateVisibleOrder (this); tree_view.UpdateScrollBars (false); // CollapseBelow if we affect the visible area if (visible_order < tree_view.skipped_nodes + tree_view.VisibleCount + 1 && ArePreviousNodesExpanded) tree_view.CollapseBelow (this, count_to_next); if(!byInternal && HasFocusInChildren ()) tree_view.SelectedNode = this; // If one or both of our scrollbars disappeared, // invalidate everything if ((hbar_visible & !tree_view.hbar.Visible) || (vbar_visible & !tree_view.vbar.Visible)) tree_view.Invalidate (); } } } private int CountToNext () { bool expanded = is_expanded; is_expanded = false; OpenTreeNodeEnumerator walk = new OpenTreeNodeEnumerator (this); TreeNode next= null; if (walk.MoveNext () && walk.MoveNext ()) next = walk.CurrentNode; is_expanded = expanded; walk.Reset (); walk.MoveNext (); int count = 0; while (walk.MoveNext () && walk.CurrentNode != next) count++; return count; } private bool HasFocusInChildren() { if (TreeView == null) return false; foreach (TreeNode node in nodes) { if(node == TreeView.SelectedNode) return true; if(node.HasFocusInChildren ()) return true; } return false; } private void ExpandRecursive (TreeNode node) { node.Expand (true); foreach (TreeNode child in node.Nodes) ExpandRecursive (child); } private void ExpandParentRecursive (TreeNode node) { node.Expand (true); if (node.Parent != null) ExpandParentRecursive (node.Parent); } internal void CollapseAll () { CollapseRecursive (this); } internal void CollapseAllUncheck () { CollapseUncheckRecursive (this); } private void CollapseRecursive (TreeNode node) { node.Collapse (); foreach (TreeNode child in node.Nodes) CollapseRecursive (child); } private void CollapseUncheckRecursive (TreeNode node) { node.Collapse (); node.Checked = false; foreach (TreeNode child in node.Nodes) CollapseUncheckRecursive (child); } internal void SetNodes (TreeNodeCollection nodes) { this.nodes = nodes; } private void GetNodeCountRecursive (TreeNode node, ref int count) { count += node.Nodes.Count; foreach (TreeNode child in node.Nodes) GetNodeCountRecursive (child, ref count); } internal bool NeedsWidth { get { return width == -1; } } internal void Invalidate () { // invalidate width first so Bounds retrieves // the updated value (we don't use it here however) width = -1; TreeView tv = TreeView; if (tv == null) return; tv.UpdateNode (this); } internal void InvalidateWidth () { // bounds.Width = 0; width = -1; } internal void SetWidth (int width) { this.width = width; } internal void SetParent (TreeNode parent) { this.parent = parent; } private bool IsInClippingRect { get { if (TreeView == null) return false; Rectangle bounds = Bounds; if (bounds.Y < 0 && bounds.Y > TreeView.ClientRectangle.Height) return false; return true; } } internal Image StateImage { get { if (TreeView != null) { if (TreeView.StateImageList == null) return null; if (state_image_index >= 0) return TreeView.StateImageList.Images[state_image_index]; if (state_image_key != string.Empty) return TreeView.StateImageList.Images[state_image_key]; } return null; } } // Order of operation: // 1) Node.Image[Key|Index] // 2) TreeView.Image[Key|Index] // 3) First image in TreeView.ImageList internal int Image { get { if (TreeView == null || TreeView.ImageList == null) return -1; if (IsSelected) { if (selected_image_index >= 0) return selected_image_index; if (!string.IsNullOrEmpty (selected_image_key)) return TreeView.ImageList.Images.IndexOfKey (selected_image_key); if (!string.IsNullOrEmpty (TreeView.SelectedImageKey)) return TreeView.ImageList.Images.IndexOfKey (TreeView.SelectedImageKey); if (TreeView.SelectedImageIndex >= 0) return TreeView.SelectedImageIndex; } else { if (image_index >= 0) return image_index; if (!string.IsNullOrEmpty (image_key)) return TreeView.ImageList.Images.IndexOfKey (image_key); if (!string.IsNullOrEmpty (TreeView.ImageKey)) return TreeView.ImageList.Images.IndexOfKey (TreeView.ImageKey); if (TreeView.ImageIndex >= 0) return TreeView.ImageIndex; } if (TreeView.ImageList.Images.Count > 0) return 0; return -1; } } #endregion // Internal & Private Methods and Properties } }