Haste vollkommen recht. Siehe mein Edit oben. Hat sich jetzt zeitlich nur überschnitten.
EDIT:
Dein Abwählen der Node hat intern ein Invalidate ausgelöst. Somit ist der Text auf dem Canvas neu gezeichnet worden und die Textbreite kann ermittelt werden. Der Tree weiß ja nicht, wie er auf deine internen Daten zugreifen soll.
Das ist so nicht ganz richtig. Dann müsste der VST die einmal gezeichnete Textbreite intern puffern. Tut er aber nicht. Tatsächlich holt er sich per GetTextMetrics regelmäßig die tatsächlichen Textbreiten vom jeweiligen DeviceContext und berechnet auch jedesmal neu. Da dürfte es eigentlich gar keine Rolle spielen ob der Node focused ist oder nicht. Welcher Text für die Berechnung verwendet werden soll wird über den Event OnGetText gesteuert. Heißt: Wird GetMaxColumnWidth aufgerufen, dann holt sich VST über OnGetText den passenden String und kalkuliert über GetTextMetrics neu.
Hmm. Von Puffern hatte ich ja auch nichts geschrieben, oder?
Es ist so, dass bei jeder Änderung des Trees, die die Oberfläche betrifft, ein Invalidate des entsprechenden Bereiches ausgelöst wird. Bei ihm wurde das gemacht, weil er die FocusedNode Property gesetzt hat und somit die "Focused Umrandung" (keine Ahnung wie ich das besser beschreiben soll, diese gepunktete Linie die angibt, dass die Node den Focus hat) auf eine andere Node bzw. auf keine Node neu gezeichnet wurde. Hierdurch wurde dann auch gleich wieder das Berechnen der Spaltenbreite ausgelöst.
Die vorherige Spaltenbreite bzw. die Breite der einzelnen Inhalte muss der Tree ja auch nicht kennen. Er durchläuft lediglich die Nodes und holt sich per GetText Event den Inhalt. Die Breite dieses Textes wird dann Canvas bezogen errechnet. Der größte Wert wird dann als Spaltenbreite übernommen. Dazu kommt dann noch TextMargins + NodeLevel(Node) * Indent usw.