Forum: PC-Programmierung TreeView neu aufbauen, ohne SelectedNode zu verlieren


von Martin Altheim (Gast)


Lesenswert?

Hallo zusammen,

ich möchte mit C# und .net 2.0 einen Treeview ausgeben, der aufgeklappt 
werden kann. Die Daten die ich darin darstelle bekomme ich zyklisch als 
Liste aus einem anderen (fremden) Modul. D.h. ich muss den Treeview 
jedesmal von Grund auf neu aufbauen.
Wenn der Benutzer jetzt einen Node selektiert und mehrere Nodes 
aufgeklappt hat, ich dann den Treeview aber neuzeichne (d.h. Treeview 
löschen und neue Nodes hinzufüge), dann sind alle Nodes zugeklappt und 
der SelectedNode ist auch nicht mehr ausgewählt.

Frage: Wie merkt man sich am besten welche Nodes aufgeklappt waren? Ich 
suche hier noch eine geniale Idee.

Eine Möglichkeit ist natürlich über alle Nodes manuell(!!) zu schleifen 
(eine Liste ALLER TreeNodes gibt es ja nicht) um deren 
IsExpanded-Eigenschaft abzufragen und das zugehörige .Tag abzuspeichern, 
um anschliessend über das Tag und diese Liste die neu gezeichneten Nodes 
wieder aufzuklappen. Das ist aber sehr umständlich und codeintensiv, 
zumal der Treeview bis zu 5 Ebenen tief ausgibt.

Wie löst ihr das Problem?

Danke und Gruß,
 Martin.

von faustian (Gast)


Lesenswert?

Bin jetzt nicht in dieser Bibliothek "drin"... aber gibts fuer das Auf- 
und zuklappen sowie Selektieren denn keinen Event, an den man einen 
Handler haengen kann der den Status zwischenspeichert?

von Markus V. (Gast)


Lesenswert?

Hi Martin,

wo ist das Problem? Du kannst abfragen, welches der selektierte Knoten 
ist, ob ein Knoten aufgeklappt ist. Ggf. mußt Du an den Knoten einen 
Verweis hängen, welcher Deiner Datensätze mit welchem Knoten verbunden 
ist (TreeNode.Tag Property).

Mit diesen Informationen (alter TreeView und neu erhaltene Daten) ist es 
möglich, im Hintergrund einen neuen TreeView aufzubauen.

Unabhängig davon würde ich ein eigenständiges Datenmodell führen (im 
Hintergrund, OHNE TreeView), das bei strukturellen Änderungen des Trees 
ein Event auslöst, das den TreeView anpasst. In diesem Datenmodell 
kannst Du alle relevanten Informationen halten.

Gruß
Markus

von Martin Altheim (Gast)


Lesenswert?

> Mit diesen Informationen (alter TreeView und neu erhaltene Daten) ist es
> möglich, im Hintergrund einen neuen TreeView aufzubauen.
Mache ich ja alles bereits genau so. Allerdings erscheint es mir relativ 
umständlich zu ermitteln, welcher Node denn jetzt aufgeklappt ist, weil
über jede Ebene separat iteriert werden muss. Und ich an der 
Tag-Eigenschaft nicht immer den gleichen Datentyp dranhängen habe (das 
ist je nach Ebene unterschiedlich).

> Unabhängig davon würde ich ein eigenständiges Datenmodell führen (im
> Hintergrund, OHNE TreeView), das bei strukturellen Änderungen des Trees
> ein Event auslöst, das den TreeView anpasst. In diesem Datenmodell
> kannst Du alle relevanten Informationen halten.
Ein eigenständige Datenmodell liegt ja bereits vor (das was ich zyklisch 
übergeben bekomme). Du meinst aber wohl, dass noch ein weiteres angelegt 
werden soll, das nur für die Treeview-Darstellung existiert?

Ok, dann könnte ich durch Vergleiche zwischen meinem Datenmodell und dem 
gelieferten Modell feststellen, welche Daten sich geändert haben und 
daraufhin meine Nodes aktualisieren/hinzufügen/entfernen, aber nicht den 
gesamten Treeview löschen und wieder von Grund auf neu aufbauen. Dann 
entfiele das Problem mit dem SelectedNode und den ExpandedNodes...

Habe ich das so im Prinzip richtig verstanden?


Eventgesteuert kann ich das leider nicht machen(?), da ich ja nur eine 
vollständige fertige Liste bekomme und beim "Erzeuger" der Liste keine 
Events auslösen möchte, um die Verstrickung der Programmteile nicht 
unnötig zu erhöhen.


Danke

von Karl H. (kbuchegg)


Lesenswert?

Martin Altheim wrote:
>> Mit diesen Informationen (alter TreeView und neu erhaltene Daten) ist es
>> möglich, im Hintergrund einen neuen TreeView aufzubauen.
> Mache ich ja alles bereits genau so. Allerdings erscheint es mir relativ
> umständlich zu ermitteln, welcher Node denn jetzt aufgeklappt ist, weil
> über jede Ebene separat iteriert werden muss.

Ja, so ist das nun mal, wenn man eine bereits in Anzeige befindliche 
Datenstruktur austauscht.

> Ok, dann könnte ich durch Vergleiche zwischen meinem Datenmodell und dem
> gelieferten Modell feststellen, welche Daten sich geändert haben und
> daraufhin meine Nodes aktualisieren/hinzufügen/entfernen, aber nicht den
> gesamten Treeview löschen und wieder von Grund auf neu aufbauen. Dann
> entfiele das Problem mit dem SelectedNode und den ExpandedNodes...
>
> Habe ich das so im Prinzip richtig verstanden?

Yep. Meistens geh ich diesen Weg.

> Eventgesteuert kann ich das leider nicht machen(?), da ich ja nur eine
> vollständige fertige Liste bekomme und beim "Erzeuger" der Liste keine
> Events auslösen möchte, um die Verstrickung der Programmteile nicht
> unnötig zu erhöhen.

Eine andere Möglichkeit ist es natürlich, wenn du dir selbst nochmal 
einen Baum aufbaust, in dem du die angelieferten Daten mit 
anzeigespezischen Attributen verknüpfst. Dann kannst du wieder auf 
Events gehen und in deinem erweitertem Baum die entsprechenden 
Markierungen anbringen. Aber am Abgleich und der Übernahme dieser 
Attribute in den neu angelieferten Baum führt auch dann kein Weg vorbei.

von Markus V. (Gast)


Lesenswert?

>Mache ich ja alles bereits genau so. Allerdings erscheint es mir relativ
>umständlich zu ermitteln, welcher Node denn jetzt aufgeklappt ist, weil
>über jede Ebene separat iteriert werden muss. Und ich an der
>Tag-Eigenschaft nicht immer den gleichen Datentyp dranhängen habe (das
>ist je nach Ebene unterschiedlich).
Ein Baum ist eine rekursive Datenstruktur. Es ist vergleichsweise 
einfach, rekursive Software darauf loszulassen. Um das Problem der 
"unterschiedlichen" Datentypen zu erschlagen, gibt es Klassen, 
Interfaces und/oder Ableitungshierarchien.

>Ein eigenständige Datenmodell liegt ja bereits vor (das was ich zyklisch
>übergeben bekomme). Du meinst aber wohl, dass noch ein weiteres angelegt
>werden soll, das nur für die Treeview-Darstellung existiert?
Ja, so ähnlich. Wie Karl heinz Buchegger schreibt, verbietet Dir 
niemand, im Hintergrund ein Datenmodell zu führen, das ebenfalls eine 
Baumstruktur hat. Dieses Datenmodell ist unabhängig vom TreeView, der 
TreeView seinerseits hängt aber direkt vom Datenmodell ab.

>Eventgesteuert kann ich das leider nicht machen(?), da ich ja nur eine
>vollständige fertige Liste bekomme und beim "Erzeuger" der Liste keine
>Events auslösen möchte, um die Verstrickung der Programmteile nicht
>unnötig zu erhöhen.
Die Events löst Dein Datenmodell aus, wenn es sich ändert. Das mußt Du 
natürlich selbst implementieren. In .NET verwendet man hierzu Delegates. 
Beispiele hierfür findest Du im Netz zuhauf. Konsumiert werden die 
Events des Datenmodells vom (Tree)View, der sich dann entsprechend 
aktualisieren kann. Man erreicht dadurch eine Entkoppelung von 
Datenmodell und Datenvisualisierung. Das kann man auch anders machen 
(z.B. den View vom Modell aus direkt referenzieren), hat dann aber eine 
Abhängigkeit des Modells vom View, die i.d.R. recht störend ist.

Gruß
Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.