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.
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?
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
> 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
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.
>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