1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
4 using System
.Collections
.Generic
;
5 using System
.Collections
.ObjectModel
;
6 using System
.ComponentModel
;
8 using System
.Security
.Permissions
;
9 using System
.Threading
;
10 using System
.Windows
.Forms
;
11 using System
.Collections
;
13 using Aga
.Controls
.Tree
.NodeControls
;
14 using Aga
.Controls
.Threading
;
17 namespace Aga
.Controls
.Tree
20 /// Extensible advanced <see cref="TreeView"/> implemented in 100% managed C# code.
21 /// Features: Model/View architecture. Multiple column per node. Ability to select
22 /// multiple tree nodes. Different types of controls for each node column:
23 /// <see cref="CheckBox"/>, Icon, Label... Drag and Drop highlighting. Load on
24 /// demand of nodes. Incremental search of nodes.
26 public partial class TreeViewAdv
: Control
28 private const int LeftMargin
= 7;
29 internal const int ItemDragSensivity
= 4;
30 private readonly int _columnHeaderHeight
;
31 private const int DividerWidth
= 9;
32 private const int DividerCorrectionGap
= -2;
36 private bool _suspendUpdate
;
37 private bool _needFullUpdate
;
38 private bool _fireSelectionEvent
;
39 private NodePlusMinus _plusMinus
;
40 private ToolTip _toolTip
;
41 private DrawContext _measureContext
;
42 private TreeColumn _hotColumn
;
43 private IncrementalSearch _search
;
44 private List
<TreeNodeAdv
> _expandingNodes
= new List
<TreeNodeAdv
>();
45 private AbortableThreadPool _threadPool
= new AbortableThreadPool();
47 public VScrollBar VScrollBar { get { return _vScrollBar; }
}
52 public event ItemDragEventHandler ItemDrag
;
53 private void OnItemDrag(MouseButtons buttons
, object item
)
56 ItemDrag(this, new ItemDragEventArgs(buttons
, item
));
59 [Category("Behavior")]
60 public event EventHandler
<TreeNodeAdvMouseEventArgs
> NodeMouseClick
;
61 private void OnNodeMouseClick(TreeNodeAdvMouseEventArgs args
)
63 if (NodeMouseClick
!= null)
64 NodeMouseClick(this, args
);
67 [Category("Behavior")]
68 public event EventHandler
<TreeNodeAdvMouseEventArgs
> NodeMouseDoubleClick
;
69 private void OnNodeMouseDoubleClick(TreeNodeAdvMouseEventArgs args
)
71 if (NodeMouseDoubleClick
!= null)
72 NodeMouseDoubleClick(this, args
);
75 [Category("Behavior")]
76 public event EventHandler
<TreeColumnEventArgs
> ColumnWidthChanged
;
77 internal void OnColumnWidthChanged(TreeColumn column
)
79 if (ColumnWidthChanged
!= null)
80 ColumnWidthChanged(this, new TreeColumnEventArgs(column
));
83 [Category("Behavior")]
84 public event EventHandler
<TreeColumnEventArgs
> ColumnReordered
;
85 internal void OnColumnReordered(TreeColumn column
)
87 if (ColumnReordered
!= null)
88 ColumnReordered(this, new TreeColumnEventArgs(column
));
91 [Category("Behavior")]
92 public event EventHandler
<TreeColumnEventArgs
> ColumnClicked
;
93 internal void OnColumnClicked(TreeColumn column
)
95 if (ColumnClicked
!= null)
96 ColumnClicked(this, new TreeColumnEventArgs(column
));
99 [Category("Behavior")]
100 public event EventHandler SelectionChanged
;
101 internal void OnSelectionChanged()
103 if (SuspendSelectionEvent
)
104 _fireSelectionEvent
= true;
107 _fireSelectionEvent
= false;
108 if (SelectionChanged
!= null)
109 SelectionChanged(this, EventArgs
.Empty
);
113 [Category("Behavior")]
114 public event EventHandler
<TreeViewAdvEventArgs
> Collapsing
;
115 private void OnCollapsing(TreeNodeAdv node
)
117 if (Collapsing
!= null)
118 Collapsing(this, new TreeViewAdvEventArgs(node
));
121 [Category("Behavior")]
122 public event EventHandler
<TreeViewAdvEventArgs
> Collapsed
;
123 private void OnCollapsed(TreeNodeAdv node
)
125 if (Collapsed
!= null)
126 Collapsed(this, new TreeViewAdvEventArgs(node
));
129 [Category("Behavior")]
130 public event EventHandler
<TreeViewAdvEventArgs
> Expanding
;
131 private void OnExpanding(TreeNodeAdv node
)
133 if (Expanding
!= null)
134 Expanding(this, new TreeViewAdvEventArgs(node
));
137 [Category("Behavior")]
138 public event EventHandler
<TreeViewAdvEventArgs
> Expanded
;
139 private void OnExpanded(TreeNodeAdv node
)
141 if (Expanded
!= null)
142 Expanded(this, new TreeViewAdvEventArgs(node
));
145 [Category("Behavior")]
146 public event EventHandler GridLineStyleChanged
;
147 private void OnGridLineStyleChanged()
149 if (GridLineStyleChanged
!= null)
150 GridLineStyleChanged(this, EventArgs
.Empty
);
153 [Category("Behavior")]
154 public event ScrollEventHandler Scroll
;
155 protected virtual void OnScroll(ScrollEventArgs e
)
161 [Category("Behavior")]
162 public event EventHandler
<TreeViewRowDrawEventArgs
> RowDraw
;
163 protected virtual void OnRowDraw(PaintEventArgs e
, TreeNodeAdv node
, DrawContext context
, int row
, Rectangle rowRect
)
167 TreeViewRowDrawEventArgs args
= new TreeViewRowDrawEventArgs(e
.Graphics
, e
.ClipRectangle
, node
, context
, row
, rowRect
);
173 /// Fires when control is going to draw. Can be used to change text or back color
175 [Category("Behavior")]
176 public event EventHandler
<DrawEventArgs
> DrawControl
;
178 internal bool DrawControlMustBeFired()
180 return DrawControl
!= null;
183 internal void FireDrawControl(DrawEventArgs args
)
188 protected virtual void OnDrawControl(DrawEventArgs args
)
190 if (DrawControl
!= null)
191 DrawControl(this, args
);
195 [Category("Drag Drop")]
196 public event EventHandler
<DropNodeValidatingEventArgs
> DropNodeValidating
;
197 protected virtual void OnDropNodeValidating(Point point
, ref TreeNodeAdv node
)
199 if (DropNodeValidating
!= null)
201 DropNodeValidatingEventArgs args
= new DropNodeValidatingEventArgs(point
, node
);
202 DropNodeValidating(this, args
);
210 InitializeComponent();
211 SetStyle(ControlStyles
.AllPaintingInWmPaint
212 | ControlStyles
.UserPaint
213 | ControlStyles
.OptimizedDoubleBuffer
214 | ControlStyles
.ResizeRedraw
215 | ControlStyles
.Selectable
219 if (Application
.RenderWithVisualStyles
)
220 _columnHeaderHeight
= 20;
222 _columnHeaderHeight
= 17;
224 //BorderStyle = BorderStyle.Fixed3D;
225 _hScrollBar
.Height
= SystemInformation
.HorizontalScrollBarHeight
;
226 _vScrollBar
.Width
= SystemInformation
.VerticalScrollBarWidth
;
227 _rowLayout
= new FixedRowHeightLayout(this, RowHeight
);
228 _rowMap
= new List
<TreeNodeAdv
>();
229 _selection
= new List
<TreeNodeAdv
>();
230 _readonlySelection
= new ReadOnlyCollection
<TreeNodeAdv
>(_selection
);
231 _columns
= new TreeColumnCollection(this);
232 _toolTip
= new ToolTip();
234 _measureContext
= new DrawContext();
235 _measureContext
.Font
= Font
;
236 _measureContext
.Graphics
= Graphics
.FromImage(new Bitmap(1, 1));
238 Input
= new NormalInputState(this);
239 _search
= new IncrementalSearch(this);
245 _plusMinus
= new NodePlusMinus();
246 _controls
= new NodeControlsCollection(this);
249 ExpandingIcon
.IconChanged
+= ExpandingIconChanged
;
252 void ExpandingIconChanged(object sender
, EventArgs e
)
254 if (IsHandleCreated
&& !IsDisposed
)
255 BeginInvoke(new MethodInvoker(DrawIcons
));
258 private void DrawIcons()
260 using (Graphics gr
= Graphics
.FromHwnd(this.Handle
))
262 //Apply the same Graphics Transform logic as used in OnPaint.
266 y
+= ColumnHeaderHeight
;
267 if (Columns
.Count
== 0)
270 int firstRowY
= _rowLayout
.GetRowBounds(FirstVisibleRow
).Y
;
273 gr
.TranslateTransform(-OffsetX
, y
);
275 DrawContext context
= new DrawContext();
276 context
.Graphics
= gr
;
277 for (int i
= 0; i
< _expandingNodes
.Count
; i
++)
279 foreach (NodeControlInfo item
in GetNodeControls(_expandingNodes
[i
]))
281 if (item
.Control
is ExpandingIcon
)
283 Rectangle bounds
= item
.Bounds
;
284 if (item
.Node
.Parent
== null && UseColumns
)
285 bounds
.Location
= Point
.Empty
; // display root expanding icon at 0,0
287 context
.Bounds
= bounds
;
288 item
.Control
.Draw(item
.Node
, context
);
295 #region Public Methods
297 public TreePath
GetPath(TreeNodeAdv node
)
300 return TreePath
.Empty
;
303 Stack
<object> stack
= new Stack
<object>();
304 while (node
!= _root
&& node
!= null)
306 stack
.Push(node
.Tag
);
309 return new TreePath(stack
.ToArray());
313 public TreeNodeAdv
GetNodeAt(Point point
)
315 NodeControlInfo info
= GetNodeControlInfoAt(point
);
319 public NodeControlInfo
GetNodeControlInfoAt(Point point
)
321 if (point
.X
< 0 || point
.Y
< 0)
322 return NodeControlInfo
.Empty
;
324 int row
= _rowLayout
.GetRowAt(point
);
325 if (row
< RowCount
&& row
>= 0)
326 return GetNodeControlInfoAt(RowMap
[row
], point
);
328 return NodeControlInfo
.Empty
;
331 private NodeControlInfo
GetNodeControlInfoAt(TreeNodeAdv node
, Point point
)
333 Rectangle rect
= _rowLayout
.GetRowBounds(FirstVisibleRow
);
334 point
.Y
+= (rect
.Y
- ColumnHeaderHeight
);
336 foreach (NodeControlInfo info
in GetNodeControls(node
))
337 if (info
.Bounds
.Contains(point
))
341 return new NodeControlInfo(null, Rectangle
.Empty
, node
);
343 return NodeControlInfo
.Empty
;
346 public void BeginUpdate()
348 _suspendUpdate
= true;
349 SuspendSelectionEvent
= true;
352 public void EndUpdate()
354 _suspendUpdate
= false;
359 SuspendSelectionEvent
= false;
362 public void ExpandAll()
367 public void CollapseAll()
373 /// Expand all parent nodes, andd scroll to the specified node
375 public void EnsureVisible(TreeNodeAdv node
)
378 throw new ArgumentNullException("node");
381 throw new ArgumentException();
383 TreeNodeAdv parent
= node
.Parent
;
384 while (parent
!= _root
)
386 parent
.IsExpanded
= true;
387 parent
= parent
.Parent
;
393 /// Make node visible, scroll if needed. All parent nodes of the specified node must be expanded
395 /// <param name="node"></param>
396 public void ScrollTo(TreeNodeAdv node
)
399 throw new ArgumentNullException("node");
402 throw new ArgumentException();
409 if (node
.Row
< FirstVisibleRow
)
413 int pageStart
= _rowLayout
.GetRowBounds(FirstVisibleRow
).Top
;
414 int rowBottom
= _rowLayout
.GetRowBounds(node
.Row
).Bottom
;
415 if (rowBottom
> pageStart
+ DisplayRectangle
.Height
- ColumnHeaderHeight
)
416 row
= _rowLayout
.GetFirstRow(node
.Row
);
419 if (row
>= _vScrollBar
.Minimum
&& row
<= _vScrollBar
.Maximum
)
420 _vScrollBar
.Value
= row
;
423 public void ClearSelection()
428 ClearSelectionInternal();
436 internal void ClearSelectionInternal()
438 while (Selection
.Count
> 0)
440 var t
= Selection
[0];
441 t
.IsSelected
= false;
442 Selection
.Remove(t
); //hack
448 protected override void OnSizeChanged(EventArgs e
)
451 SafeUpdateScrollBars();
452 base.OnSizeChanged(e
);
455 private void ArrangeControls()
457 int hBarSize
= _hScrollBar
.Height
;
458 int vBarSize
= _vScrollBar
.Width
;
459 Rectangle clientRect
= ClientRectangle
;
461 _hScrollBar
.SetBounds(clientRect
.X
, clientRect
.Bottom
- hBarSize
,
462 clientRect
.Width
- vBarSize
, hBarSize
);
464 _vScrollBar
.SetBounds(clientRect
.Right
- vBarSize
, clientRect
.Y
,
465 vBarSize
, clientRect
.Height
- hBarSize
);
468 private void SafeUpdateScrollBars()
471 BeginInvoke(new MethodInvoker(UpdateScrollBars
));
476 private void UpdateScrollBars()
482 _hScrollBar
.Width
= DisplayRectangle
.Width
;
483 _vScrollBar
.Height
= DisplayRectangle
.Height
;
486 private void UpdateHScrollBar()
488 _hScrollBar
.Maximum
= ContentWidth
;
489 _hScrollBar
.LargeChange
= Math
.Max(DisplayRectangle
.Width
, 0);
490 _hScrollBar
.SmallChange
= 5;
491 _hScrollBar
.Visible
= _hScrollBar
.LargeChange
< _hScrollBar
.Maximum
;
492 _hScrollBar
.Value
= Math
.Min(_hScrollBar
.Value
, _hScrollBar
.Maximum
- _hScrollBar
.LargeChange
+ 1);
495 private void UpdateVScrollBar()
497 _vScrollBar
.Maximum
= Math
.Max(RowCount
- 1, 0);
498 _vScrollBar
.LargeChange
= _rowLayout
.PageRowCount
;
499 _vScrollBar
.Visible
= (RowCount
> 0) && (_vScrollBar
.LargeChange
<= _vScrollBar
.Maximum
);
500 _vScrollBar
.Value
= Math
.Min(_vScrollBar
.Value
, _vScrollBar
.Maximum
- _vScrollBar
.LargeChange
+ 1);
503 protected override CreateParams CreateParams
505 [SecurityPermission(SecurityAction
.LinkDemand
, Flags
= SecurityPermissionFlag
.UnmanagedCode
)]
508 CreateParams res
= base.CreateParams
;
511 case BorderStyle
.FixedSingle
:
512 res
.Style
|= 0x800000;
514 case BorderStyle
.Fixed3D
:
515 res
.ExStyle
|= 0x200;
522 protected override void OnGotFocus(EventArgs e
)
529 protected override void OnFontChanged(EventArgs e
)
531 base.OnFontChanged(e
);
532 _measureContext
.Font
= Font
;
536 internal IEnumerable
<NodeControlInfo
> GetNodeControls(TreeNodeAdv node
)
540 Rectangle rowRect
= _rowLayout
.GetRowBounds(node
.Row
);
541 foreach (NodeControlInfo n
in GetNodeControls(node
, rowRect
))
545 internal IEnumerable
<NodeControlInfo
> GetNodeControls(TreeNodeAdv node
, Rectangle rowRect
)
551 int x
= (node
.Level
- 1) * _indent
+ LeftMargin
;
553 if (node
.Row
== 0 && ShiftFirstNode
)
555 Rectangle rect
= Rectangle
.Empty
;
559 width
= _plusMinus
.GetActualSize(node
, _measureContext
).Width
;
560 rect
= new Rectangle(x
, y
, width
, rowRect
.Height
);
561 if (UseColumns
&& Columns
.Count
> 0 && Columns
[0].Width
< rect
.Right
)
562 rect
.Width
= Columns
[0].Width
- x
;
564 yield return new NodeControlInfo(_plusMinus
, rect
, node
);
570 foreach (NodeControl c
in NodeControls
)
572 Size s
= c
.GetActualSize(node
, _measureContext
);
576 rect
= new Rectangle(x
, y
, width
, rowRect
.Height
);
578 yield return new NodeControlInfo(c
, rect
, node
);
585 foreach (TreeColumn col
in Columns
)
587 if (col
.IsVisible
&& col
.Width
> 0)
590 for (int i
= 0; i
< NodeControls
.Count
; i
++)
592 NodeControl nc
= NodeControls
[i
];
593 if (nc
.ParentColumn
== col
)
595 Size s
= nc
.GetActualSize(node
, _measureContext
);
598 bool isLastControl
= true;
599 for (int k
= i
+ 1; k
< NodeControls
.Count
; k
++)
600 if (NodeControls
[k
].ParentColumn
== col
)
602 isLastControl
= false;
609 int maxWidth
= Math
.Max(0, right
- x
);
610 rect
= new Rectangle(x
, y
, Math
.Min(maxWidth
, width
), rowRect
.Height
);
612 yield return new NodeControlInfo(nc
, rect
, node
);
622 internal static double Dist(Point p1
, Point p2
)
624 return Math
.Sqrt(Math
.Pow(p1
.X
- p2
.X
, 2) + Math
.Pow(p1
.Y
- p2
.Y
, 2));
627 public void FullUpdate()
631 BeginInvoke(new MethodInvoker(UnsafeFullUpdate
));
636 private void UnsafeFullUpdate()
638 _rowLayout
.ClearCache();
640 SafeUpdateScrollBars();
642 _needFullUpdate
= false;
645 internal void UpdateView()
651 internal void UpdateHeaders()
653 Invalidate(new Rectangle(0, 0, Width
, ColumnHeaderHeight
));
656 internal void UpdateColumns()
661 private void CreateNodes()
664 SelectionStart
= null;
665 _root
= new TreeNodeAdv(this, null);
666 _root
.IsExpanded
= true;
667 if (_root
.Nodes
.Count
> 0)
668 CurrentNode
= _root
.Nodes
[0];
673 internal void ReadChilds(TreeNodeAdv parentNode
)
675 ReadChilds(parentNode
, false);
678 internal void ReadChilds(TreeNodeAdv parentNode
, bool performFullUpdate
)
680 if (!parentNode
.IsLeaf
)
682 parentNode
.IsExpandedOnce
= true;
683 parentNode
.Nodes
.Clear();
687 IEnumerable items
= Model
.GetChildren(GetPath(parentNode
));
689 foreach (object obj
in items
)
691 AddNewNode(parentNode
, obj
, -1);
692 if (performFullUpdate
)
697 if (parentNode
.AutoExpandOnStructureChanged
)
698 parentNode
.ExpandAll();
702 private void AddNewNode(TreeNodeAdv parent
, object tag
, int index
)
704 TreeNodeAdv node
= new TreeNodeAdv(this, tag
);
705 AddNode(parent
, index
, node
);
708 private void AddNode(TreeNodeAdv parent
, int index
, TreeNodeAdv node
)
710 if (index
>= 0 && index
< parent
.Nodes
.Count
)
711 parent
.Nodes
.Insert(index
, node
);
713 parent
.Nodes
.Add(node
);
715 node
.IsLeaf
= Model
.IsLeaf(GetPath(node
));
718 if (!LoadOnDemand
|| node
.IsExpandedOnce
)
722 private struct ExpandArgs
724 public TreeNodeAdv Node
;
726 public bool IgnoreChildren
;
729 public void AbortBackgroundExpandingThreads()
731 _threadPool
.CancelAll(true);
732 for (int i
= 0; i
< _expandingNodes
.Count
; i
++)
733 _expandingNodes
[i
].IsExpandingNow
= false;
734 _expandingNodes
.Clear();
738 internal void SetIsExpanded(TreeNodeAdv node
, bool value, bool ignoreChildren
)
740 ExpandArgs eargs
= new ExpandArgs();
743 eargs
.IgnoreChildren
= ignoreChildren
;
745 if (AsyncExpanding
&& LoadOnDemand
&& !_threadPool
.IsMyThread(Thread
.CurrentThread
))
747 WaitCallback wc
= delegate(object argument
) { SetIsExpanded((ExpandArgs)argument); }
;
748 _threadPool
.QueueUserWorkItem(wc
, eargs
);
751 SetIsExpanded(eargs
);
754 private void SetIsExpanded(ExpandArgs eargs
)
756 bool update
= !eargs
.IgnoreChildren
&& !AsyncExpanding
;
761 if (IsMyNode(eargs
.Node
) && eargs
.Node
.IsExpanded
!= eargs
.Value
)
762 SetIsExpanded(eargs
.Node
, eargs
.Value
);
764 if (!eargs
.IgnoreChildren
)
765 SetIsExpandedRecursive(eargs
.Node
, eargs
.Value
);
774 internal void SetIsExpanded(TreeNodeAdv node
, bool value)
776 if (Root
== node
&& !value)
777 return; //Can't collapse root node
790 if (value && !node
.IsExpandedOnce
)
792 if (AsyncExpanding
&& LoadOnDemand
)
794 AddExpandingNode(node
);
795 node
.AssignIsExpanded(true);
798 ReadChilds(node
, AsyncExpanding
);
799 RemoveExpandingNode(node
);
801 node
.AssignIsExpanded(value);
816 private void RemoveExpandingNode(TreeNodeAdv node
)
818 node
.IsExpandingNow
= false;
819 _expandingNodes
.Remove(node
);
820 if (_expandingNodes
.Count
<= 0)
821 ExpandingIcon
.Stop();
824 private void AddExpandingNode(TreeNodeAdv node
)
826 node
.IsExpandingNow
= true;
827 _expandingNodes
.Add(node
);
828 ExpandingIcon
.Start();
831 internal void SetIsExpandedRecursive(TreeNodeAdv root
, bool value)
833 for (int i
= 0; i
< root
.Nodes
.Count
; i
++)
835 TreeNodeAdv node
= root
.Nodes
[i
];
836 node
.IsExpanded
= value;
837 SetIsExpandedRecursive(node
, value);
841 private void CreateRowMap()
846 foreach (TreeNodeAdv node
in VisibleNodes
)
852 _contentWidth
= Math
.Max(_contentWidth
, GetNodeWidth(node
));
859 foreach (TreeColumn col
in _columns
)
861 _contentWidth
+= col
.Width
;
865 private int GetNodeWidth(TreeNodeAdv node
)
867 if (node
.RightBounds
== null)
869 Rectangle res
= GetNodeBounds(GetNodeControls(node
, Rectangle
.Empty
));
870 node
.RightBounds
= res
.Right
;
872 return node
.RightBounds
.Value
;
875 internal Rectangle
GetNodeBounds(TreeNodeAdv node
)
877 return GetNodeBounds(GetNodeControls(node
));
880 private Rectangle
GetNodeBounds(IEnumerable
<NodeControlInfo
> nodeControls
)
882 Rectangle res
= Rectangle
.Empty
;
883 foreach (NodeControlInfo info
in nodeControls
)
885 if (res
== Rectangle
.Empty
)
888 res
= Rectangle
.Union(res
, info
.Bounds
);
893 private void _vScrollBar_ValueChanged(object sender
, EventArgs e
)
895 FirstVisibleRow
= _vScrollBar
.Value
;
898 private void _hScrollBar_ValueChanged(object sender
, EventArgs e
)
900 OffsetX
= _hScrollBar
.Value
;
903 private void _vScrollBar_Scroll(object sender
, ScrollEventArgs e
)
908 private void _hScrollBar_Scroll(object sender
, ScrollEventArgs e
)
913 internal void SmartFullUpdate()
916 _needFullUpdate
= true;
921 internal bool IsMyNode(TreeNodeAdv node
)
926 if (node
.Tree
!= this)
929 while (node
.Parent
!= null)
932 return node
== _root
;
935 internal void UpdateSelection()
939 if (!IsMyNode(CurrentNode
))
941 if (!IsMyNode(_selectionStart
))
942 _selectionStart
= null;
944 for (int i
= Selection
.Count
- 1; i
>= 0; i
--)
945 if (!IsMyNode(Selection
[i
]))
948 Selection
.RemoveAt(i
);
952 OnSelectionChanged();
955 internal void ChangeColumnWidth(TreeColumn column
)
957 if (!(_input
is ResizeColumnState
))
960 OnColumnWidthChanged(column
);
964 public TreeNodeAdv
FindNode(TreePath path
)
966 return FindNode(path
, false);
969 public TreeNodeAdv
FindNode(TreePath path
, bool readChilds
)
974 return FindNode(_root
, path
, 0, readChilds
);
977 private TreeNodeAdv
FindNode(TreeNodeAdv root
, TreePath path
, int level
, bool readChilds
)
979 if (!root
.IsExpandedOnce
&& readChilds
)
982 for (int i
= 0; i
< root
.Nodes
.Count
; i
++)
984 TreeNodeAdv node
= root
.Nodes
[i
];
985 if (node
.Tag
== path
.FullPath
[level
])
987 if (level
== path
.FullPath
.Length
- 1)
990 return FindNode(node
, path
, level
+ 1, readChilds
);
996 public TreeNodeAdv
FindNodeByTag(object tag
)
998 return FindNodeByTag(_root
, tag
);
1001 private TreeNodeAdv
FindNodeByTag(TreeNodeAdv root
, object tag
)
1003 foreach (TreeNodeAdv node
in root
.Nodes
)
1005 if (node
.Tag
== tag
)
1007 TreeNodeAdv res
= FindNodeByTag(node
, tag
);
1014 public void SelectAllNodes()
1016 SuspendSelectionEvent
= true;
1019 if (SelectionMode
== TreeSelectionMode
.MultiSameParent
)
1021 if (CurrentNode
!= null)
1023 foreach (TreeNodeAdv n
in CurrentNode
.Parent
.Nodes
)
1024 n
.IsSelected
= true;
1027 else if (SelectionMode
== TreeSelectionMode
.Multi
)
1029 SelectNodes(Root
.Nodes
);
1034 SuspendSelectionEvent
= false;
1038 private void SelectNodes(Collection
<TreeNodeAdv
> nodes
)
1040 foreach (TreeNodeAdv n
in nodes
)
1042 n
.IsSelected
= true;
1044 SelectNodes(n
.Nodes
);
1049 private void BindModelEvents()
1051 _model
.NodesChanged
+= new EventHandler
<TreeModelEventArgs
>(_model_NodesChanged
);
1052 _model
.NodesInserted
+= new EventHandler
<TreeModelEventArgs
>(_model_NodesInserted
);
1053 _model
.NodesRemoved
+= new EventHandler
<TreeModelEventArgs
>(_model_NodesRemoved
);
1054 _model
.StructureChanged
+= new EventHandler
<TreePathEventArgs
>(_model_StructureChanged
);
1057 private void UnbindModelEvents()
1059 _model
.NodesChanged
-= new EventHandler
<TreeModelEventArgs
>(_model_NodesChanged
);
1060 _model
.NodesInserted
-= new EventHandler
<TreeModelEventArgs
>(_model_NodesInserted
);
1061 _model
.NodesRemoved
-= new EventHandler
<TreeModelEventArgs
>(_model_NodesRemoved
);
1062 _model
.StructureChanged
-= new EventHandler
<TreePathEventArgs
>(_model_StructureChanged
);
1065 private void _model_StructureChanged(object sender
, TreePathEventArgs e
)
1068 throw new ArgumentNullException();
1070 TreeNodeAdv node
= FindNode(e
.Path
);
1074 node
.IsLeaf
= Model
.IsLeaf(GetPath(node
));
1076 var list
= new Dictionary
<object, object>();
1077 SaveExpandedNodes(node
, list
);
1079 RestoreExpandedNodes(node
, list
);
1085 // throw new ArgumentException("Path not found");
1088 private void RestoreExpandedNodes(TreeNodeAdv node
, Dictionary
<object, object> list
)
1090 if (node
.Tag
!= null && list
.ContainsKey(node
.Tag
))
1092 node
.IsExpanded
= true;
1093 foreach (var child
in node
.Children
)
1094 RestoreExpandedNodes(child
, list
);
1098 private void SaveExpandedNodes(TreeNodeAdv node
, Dictionary
<object, object> list
)
1100 if (node
.IsExpanded
&& node
.Tag
!= null)
1102 list
.Add(node
.Tag
, null);
1103 foreach (var child
in node
.Children
)
1104 SaveExpandedNodes(child
, list
);
1108 private void _model_NodesRemoved(object sender
, TreeModelEventArgs e
)
1110 TreeNodeAdv parent
= FindNode(e
.Path
);
1113 if (e
.Indices
!= null)
1115 List
<int> list
= new List
<int>(e
.Indices
);
1117 for (int n
= list
.Count
- 1; n
>= 0; n
--)
1119 int index
= list
[n
];
1120 if (index
>= 0 && index
<= parent
.Nodes
.Count
)
1121 parent
.Nodes
.RemoveAt(index
);
1123 throw new ArgumentOutOfRangeException("Index out of range");
1128 for (int i
= parent
.Nodes
.Count
- 1; i
>= 0; i
--)
1130 for (int n
= 0; n
< e
.Children
.Length
; n
++)
1131 if (parent
.Nodes
[i
].Tag
== e
.Children
[n
])
1133 parent
.Nodes
.RemoveAt(i
);
1143 private void _model_NodesInserted(object sender
, TreeModelEventArgs e
)
1145 if (e
.Indices
== null)
1146 throw new ArgumentNullException("Indices");
1148 TreeNodeAdv parent
= FindNode(e
.Path
);
1151 for (int i
= 0; i
< e
.Children
.Length
; i
++)
1152 AddNewNode(parent
, e
.Children
[i
], e
.Indices
[i
]);
1157 private void _model_NodesChanged(object sender
, TreeModelEventArgs e
)
1159 TreeNodeAdv parent
= FindNode(e
.Path
);
1160 if (parent
!= null && parent
.IsVisible
&& parent
.IsExpanded
)
1163 BeginInvoke(new UpdateContentWidthDelegate(ClearNodesSize
), e
, parent
);
1165 ClearNodesSize(e
, parent
);
1170 private delegate void UpdateContentWidthDelegate(TreeModelEventArgs e
, TreeNodeAdv parent
);
1171 private void ClearNodesSize(TreeModelEventArgs e
, TreeNodeAdv parent
)
1173 if (e
.Indices
!= null)
1175 foreach (int index
in e
.Indices
)
1177 if (index
>= 0 && index
< parent
.Nodes
.Count
)
1179 TreeNodeAdv node
= parent
.Nodes
[index
];
1180 node
.Height
= node
.RightBounds
= null;
1183 throw new ArgumentOutOfRangeException("Index out of range");
1188 foreach (TreeNodeAdv node
in parent
.Nodes
)
1190 foreach (object obj
in e
.Children
)
1191 if (node
.Tag
== obj
)
1193 node
.Height
= node
.RightBounds
= null;