@@ -319,8 +319,13 @@ public T SelectedObject {
319319 /// <summary>
320320 /// Secondary selected regions of tree when <see cref="MultiSelect"/> is true
321321 /// </summary>
322- private Stack < TreeSelection < T > > _multiSelectedRegions = new Stack < TreeSelection < T > > ( ) ;
322+ private Stack < TreeSelection < T > > multiSelectedRegions = new Stack < TreeSelection < T > > ( ) ;
323323
324+ /// <summary>
325+ /// Cached result of <see cref="BuildLineMap"/>
326+ /// </summary>
327+ private Branch < T > [ ] cachedLineMap ;
328+
324329
325330 /// <summary>
326331 /// Error message to display when the control is not properly initialized at draw time (nodes added but no tree builder set)
@@ -400,18 +405,21 @@ public void AddObject(T o)
400405 {
401406 if ( ! roots . ContainsKey ( o ) ) {
402407 roots . Add ( o , new Branch < T > ( this , null , o ) ) ;
408+ InvalidateLineMap ( ) ;
403409 SetNeedsDisplay ( ) ;
404410 }
405411 }
406412
413+
407414 /// <summary>
408415 /// Removes all objects from the tree and clears <see cref="SelectedObject"/>
409416 /// </summary>
410417 public void ClearObjects ( )
411418 {
412419 SelectedObject = default ( T ) ;
413- _multiSelectedRegions . Clear ( ) ;
420+ multiSelectedRegions . Clear ( ) ;
414421 roots = new Dictionary < T , Branch < T > > ( ) ;
422+ InvalidateLineMap ( ) ;
415423 SetNeedsDisplay ( ) ;
416424 }
417425
@@ -424,6 +432,7 @@ public void Remove(T o)
424432 {
425433 if ( roots . ContainsKey ( o ) ) {
426434 roots . Remove ( o ) ;
435+ InvalidateLineMap ( ) ;
427436 SetNeedsDisplay ( ) ;
428437
429438 if ( Equals ( SelectedObject , o ) )
@@ -445,9 +454,11 @@ public void AddObjects(IEnumerable<T> collection)
445454 objectsAdded = true ;
446455 }
447456 }
448-
449- if ( objectsAdded )
457+
458+ if ( objectsAdded ) {
459+ InvalidateLineMap ( ) ;
450460 SetNeedsDisplay ( ) ;
461+ }
451462 }
452463
453464 /// <summary>
@@ -461,6 +472,7 @@ public void RefreshObject (T o, bool startAtTop = false)
461472 var branch = ObjectToBranch ( o ) ;
462473 if ( branch != null ) {
463474 branch . Refresh ( startAtTop ) ;
475+ InvalidateLineMap ( ) ;
464476 SetNeedsDisplay ( ) ;
465477 }
466478
@@ -474,6 +486,7 @@ public void RebuildTree()
474486 foreach ( var branch in roots . Values )
475487 branch . Rebuild ( ) ;
476488
489+ InvalidateLineMap ( ) ;
477490 SetNeedsDisplay ( ) ;
478491 }
479492
@@ -590,13 +603,16 @@ public int GetContentWidth(bool visible){
590603 /// <returns></returns>
591604 private Branch < T > [ ] BuildLineMap ( )
592605 {
606+ if ( cachedLineMap != null )
607+ return cachedLineMap ;
608+
593609 List < Branch < T > > toReturn = new List < Branch < T > > ( ) ;
594610
595611 foreach ( var root in roots . Values ) {
596612 toReturn . AddRange ( AddToLineMap ( root ) ) ;
597613 }
598614
599- return toReturn . ToArray ( ) ;
615+ return cachedLineMap = toReturn . ToArray ( ) ;
600616 }
601617
602618 private IEnumerable < Branch < T > > AddToLineMap ( Branch < T > currentBranch )
@@ -733,14 +749,14 @@ public override bool MouseEvent (MouseEvent me)
733749 clickedBranch . Expand ( ) ;
734750 else {
735751 SelectedObject = clickedBranch . Model ; // It is a leaf node
736- _multiSelectedRegions . Clear ( ) ;
752+ multiSelectedRegions . Clear ( ) ;
737753 }
738754 }
739755 else {
740756
741757 // It is a first click somewhere in the current line that doesn't look like an expansion/collapse attempt
742758 SelectedObject = clickedBranch . Model ;
743- _multiSelectedRegions . Clear ( ) ;
759+ multiSelectedRegions . Clear ( ) ;
744760 }
745761
746762 SetNeedsDisplay ( ) ;
@@ -829,7 +845,7 @@ public void AdjustSelection (int offset, bool expandSelection = false)
829845 {
830846 // if it is not a shift click or we don't allow multi select
831847 if ( ! expandSelection || ! MultiSelect )
832- _multiSelectedRegions . Clear ( ) ;
848+ multiSelectedRegions . Clear ( ) ;
833849
834850 if ( SelectedObject == null ) {
835851 SelectedObject = roots . Keys . FirstOrDefault ( ) ;
@@ -852,16 +868,16 @@ public void AdjustSelection (int offset, bool expandSelection = false)
852868 // If it is a multi selection
853869 if ( expandSelection && MultiSelect )
854870 {
855- if ( _multiSelectedRegions . Any ( ) )
871+ if ( multiSelectedRegions . Any ( ) )
856872 {
857873 // expand the existing head selection
858- var head = _multiSelectedRegions . Pop ( ) ;
859- _multiSelectedRegions . Push ( new TreeSelection < T > ( head . Origin , newIdx , map ) ) ;
874+ var head = multiSelectedRegions . Pop ( ) ;
875+ multiSelectedRegions . Push ( new TreeSelection < T > ( head . Origin , newIdx , map ) ) ;
860876 }
861877 else
862878 {
863879 // or start a new multi selection region
864- _multiSelectedRegions . Push ( new TreeSelection < T > ( map [ idx ] , newIdx , map ) ) ;
880+ multiSelectedRegions . Push ( new TreeSelection < T > ( map [ idx ] , newIdx , map ) ) ;
865881 }
866882 }
867883
@@ -882,7 +898,8 @@ public void AdjustSelection (int offset, bool expandSelection = false)
882898 }
883899
884900 }
885-
901+
902+ InvalidateLineMap ( ) ;
886903 SetNeedsDisplay ( ) ;
887904 }
888905
@@ -896,6 +913,7 @@ public void Expand(T toExpand)
896913 return ;
897914
898915 ObjectToBranch ( toExpand ) ? . Expand ( ) ;
916+ InvalidateLineMap ( ) ;
899917 SetNeedsDisplay ( ) ;
900918 }
901919
@@ -909,6 +927,7 @@ public void ExpandAll(T toExpand)
909927 return ;
910928
911929 ObjectToBranch ( toExpand ) ? . ExpandAll ( ) ;
930+ InvalidateLineMap ( ) ;
912931 SetNeedsDisplay ( ) ;
913932 }
914933 /// <summary>
@@ -919,7 +938,8 @@ public void ExpandAll()
919938 foreach ( var item in roots ) {
920939 item . Value . ExpandAll ( ) ;
921940 }
922-
941+
942+ InvalidateLineMap ( ) ;
923943 SetNeedsDisplay ( ) ;
924944 }
925945 /// <summary>
@@ -968,7 +988,8 @@ public void CollapseAll()
968988 foreach ( var item in roots ) {
969989 item . Value . Collapse ( ) ;
970990 }
971-
991+
992+ InvalidateLineMap ( ) ;
972993 SetNeedsDisplay ( ) ;
973994 }
974995
@@ -1001,8 +1022,17 @@ protected void CollapseImpl(T toCollapse, bool all)
10011022 SelectedObject = null ;
10021023 }
10031024
1025+ InvalidateLineMap ( ) ;
10041026 SetNeedsDisplay ( ) ;
10051027 }
1028+
1029+ /// <summary>
1030+ /// Clears any cached results of <see cref="BuildLineMap"/>
1031+ /// </summary>
1032+ protected void InvalidateLineMap ( )
1033+ {
1034+ cachedLineMap = null ;
1035+ }
10061036
10071037 /// <summary>
10081038 /// Returns the corresponding <see cref="Branch{T}"/> in the tree for <paramref name="toFind"/>. This will not work for objects hidden by their parent being collapsed
@@ -1022,7 +1052,7 @@ private Branch<T> ObjectToBranch(T toFind)
10221052 public bool IsSelected ( T model )
10231053 {
10241054 return Equals ( SelectedObject , model ) ||
1025- ( MultiSelect && _multiSelectedRegions . Any ( s=> s . Contains ( model ) ) ) ;
1055+ ( MultiSelect && multiSelectedRegions . Any ( s=> s . Contains ( model ) ) ) ;
10261056 }
10271057
10281058 /// <summary>
@@ -1054,14 +1084,14 @@ public void SelectAll()
10541084 if ( ! MultiSelect )
10551085 return ;
10561086
1057- _multiSelectedRegions . Clear ( ) ;
1087+ multiSelectedRegions . Clear ( ) ;
10581088
10591089 var map = BuildLineMap ( ) ;
10601090
10611091 if ( map . Length == 0 )
10621092 return ;
10631093
1064- _multiSelectedRegions . Push ( new TreeSelection < T > ( map [ 0 ] , map . Length , map ) ) ;
1094+ multiSelectedRegions . Push ( new TreeSelection < T > ( map [ 0 ] , map . Length , map ) ) ;
10651095 SetNeedsDisplay ( ) ;
10661096
10671097 OnSelectionChanged ( new SelectionChangedEventArgs < T > ( this , SelectedObject , SelectedObject ) ) ;
0 commit comments