Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
Visual C# 2005 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2005

Visual C# 2005
1.320 S., mit 2 CDs, 59,90 Euro
Galileo Computing
ISBN 3-89842-586-X
gp Kapitel 19 Weitere Steuerelemente
  gp 19.1 Bildlaufleisten mit »HScrollBar« und »VScrollBar«
  gp 19.2 Schieberegler mit der Klasse »TrackBar«
  gp 19.3 Das »ProgressBar«-Steuerelement
  gp 19.4 Drehfeld-Steuerelemente (»UpDown«-Steuerelemente)
    gp 19.4.1 Das »NumericUpDown«-Steuerelement
    gp 19.4.2 Das »DomainUpDown«-Steuerelement
  gp 19.5 Das »Timer«-Steuerelement
  gp 19.6 Die Klasse »ErrorProvider«
  gp 19.7 Steuerelemente für die Datums- und Zeitangabe
    gp 19.7.1 Das Steuerelement »MonthCalendar«
    gp 19.7.2 Das Steuerelement »DateTimePicker«
  gp 19.8 Das »Panel«-Steuerelement
  gp 19.9 Das Steuerelement »NotifyIcon«
  gp 19.10 Bildanzeige mit »PictureBox«
  gp 19.11 Eine Liste mit Symbolen mit »ImageList« bereitstellen
    gp 19.11.1 Die Eigenschaften der Klasse »ImageList«
    gp 19.11.2 Die Bildliste füllen
  gp 19.12 Registerkarten mit »TabControl«
    gp 19.12.1 Die Klasse »TabControl«
    gp 19.12.2 Objekte vom Typ »TabPage«
  gp 19.13 Das »TreeView«-Steuerelement
    gp 19.13.1 Knotenpunkte im »TreeView« definieren
    gp 19.13.2 Eigenschaften des »TreeView«-Steuerelements
    gp 19.13.3 Die Unterstützung der Entwicklungsumgebung
    gp 19.13.4 Die Ereignisse des »TreeView«-Steuerelements
    gp 19.13.5 Weitere Eigenschaften und Methoden des »TreeView«-Objekts
    gp 19.13.6 Eigenschaften und Methoden des »TreeNode«-Objekts
    gp 19.13.7 Beispiel zum Einlesen der Verzeichnisstruktur
  gp 19.14 Die beiden »Splitter«-Steuerelemente
    gp 19.14.1 Das Steuerelement »Splitter«
    gp 19.14.2 Das Steuerelement »SplitContainer«
  gp 19.15 Das »ListView«-Steuerelement
    gp 19.15.1 Die Klassen des »ListView«-Steuerelements
    gp 19.15.2 Die Eigenschaften der »ListView«
    gp 19.15.3 Listenelemente vom Typ »ListViewItem«
    gp 19.15.4 Das Element »ListViewSubItem«
    gp 19.15.5 Der Typ »ColumnHeader«
    gp 19.15.6 Listenelemente Gruppen zuordnen
    gp 19.15.7 Sortierung der Spalten
    gp 19.15.8 Listenelemente ändern
    gp 19.15.9 Beispielanwendung
  gp 19.16 BackGroundWorker


Galileo Computing

19.13 Das »TreeView«-Steuerelement  downtop

Wenn Sie den Microsoft Explorer öffnen, werden Sie in dessen Clientbereich drei Steuerelemente wieder finden, mit denen wir uns in diesem und den folgenden Abschnitten beschäftigen wollen. Im linken Teil des Fensters werden in einer hierarchischen Struktur alle verfügbaren Laufwerke aufgeführt, die sich bei einem Klick auf das »+«-Zeichen öffnen und die darin enthaltene Ordnerstruktur preisgeben. Dieses Verhalten wird durch ein TreeView-Steuerelement, das auch als Strukturansicht bezeichnet wird, bereitgestellt. Von einem Ordner werden Dateien verwaltet, die wahlweise in verschiedenen Ansichten im rechten Teil des Explorers ausgegeben werden. .NET bietet uns zu diesem Zweck das Steuerelement ListView an.

Die beiden durch ein TreeView- und ein ListView-Objekt gebildeten Teilfenster haben keine statische Breite, sondern können vom Anwender je nach Bedarf unter Beibehaltung der Breite des Fensters mit der Maus vergrößert oder verkleinert werden. Für diese Änderung ist das Steuerelement Splitter zuständig.


Galileo Computing

19.13.1 Knotenpunkte im »TreeView« definieren  downtop

Zunächst widmen wir uns dem TreeView-Control, das sich nicht nur zur Anzeige der Laufwerke und deren untergeordneten Verzeichnissen eignet, sondern auch zur Darstellung beliebiger hierarchischer Strukturen wie beispielsweise die einer Datenbank.

Betrachten Sie zunächst die folgende Abbildung, in der in einem TreeView-Steuerelement die fünf Erdteile unterhalb des Stammknotens Erde ausgegeben werden.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 19.17   Einfache Anzeige in einem »TreeView«-Steuerelement

In einem TreeView-Objekt, das auch als Strukturansicht bezeichnet wird, spielt noch eine weitere Klasse eine ganz maßgebliche Rolle: TreeNode. Ein Objekt vom Typ TreeNode entspricht einem Knoten in der Strukturansicht – unabhängig von der Position innerhalb der hierarchischen Struktur. In Abbildung 19.17 haben wir es demnach mit sechs TreeNode-Objekten zu tun: Erde, Amerika, Asien, Afrika, Australien und Europa.

Das TreeView und jeder darin angezeigte Knoten kann selbst wieder Ausgangspunkt einer Reihe weiterer untergeordneter Knoten sein. Jeder einzelne Knoten verwaltet die ihm untergeordneten Knoten in einer eigenen Auflistung vom Typ TreeNodeCollection. Das Strukturansicht-Steuerelement in der Abbildung 19.17 enthält in seiner eigenen Auflistung nur ein TreeNode-Objekt, nämlich Erde. Dieser Knoten wird von der TreeNodeCollection des Controls verwaltet, während die Elemente Amerika, Asien usw. in der TreeNodeCollection des Knotens Erde enthalten sind.

Der Referenz auf die Auflistung liefert die Eigenschaft Nodes:


public TreeNodeCollection Nodes {get;}

So wie alle anderen Auflistungen enthält auch dieser Typ Methoden, um auf die verwalteten TreeNode-Objekte zuzugreifen, neue hinzuzufügen oder verwaltete zu löschen.

Jetzt kennen Sie die wichtigsten Grundlagen, und wir können uns den Programmcode ansehen, der zu der Ausgabe in Abbildung 19.17 führt.


TreeView tr = new TreeView();
tr.Dock = DockStyle.Fill;
tr.Nodes.Add("Erde");
tr.Nodes[0].Nodes.Add("Amerika");
tr.Nodes[0].Nodes.Add("Asien");
tr.Nodes[0].Nodes.Add("Afrika");
tr.Nodes[0].Nodes.Add("Australien");
tr.Nodes[0].Nodes.Add("Europa");
this.Controls.Add(tr);

Nach der Instanziierung mit


TreeView tr = new TreeView();

sowie der Positionierung und Größenfestlegung wird das Stammelement Erde hinzugefügt, indem zu der TreeNodeCollection der Strukturansicht ein TreeNode-Objekt hinzugefügt wird:


tr.Nodes.Add("Erde");

Erde ist das erste Element in der Auflistung und hat den Index 0. Es wird auch als Stammelement bezeichnet. Sie können anstelle einer Zeichenfolge auch die Referenz auf ein TreeNode-Objekt übergeben.

Weil auch das TreeNodeCollection-Objekt, wie die meisten anderen Auflistungen, einen Indexer bereitstellt, kann man sich unter der Angabe des Index die Referenz auf ein Element besorgen und über dessen Eigenschaft Nodes wiederum die Referenz auf dessen TreeNodeCollection. Darauf lässt sich erneut die Add-Methode aufrufen, z.B.:


tr.Nodes[0].Nodes.Add("Amerika");

Alle Elemente unterhalb der Stammelemente werden als untergeordnete Elemente bezeichnet. Ein solches ist demnach auch Amerika. In gleicher Weise lassen sich auch die anderen Erdteile der Auflistung hinzufügen.

Alternativ bietet sich auch die AddRange-Methode an, die ein Array vom Typ TreeNode entgegennimmt.


TreeNode[] nodesErde = new TreeNode[]{                        new TreeNode("Amerika"),                        new TreeNode("Asien"),                        new TreeNode("Afrika"),                        new TreeNode("Australien"),                        new TreeNode("Europa")};
tr.Nodes[0].Nodes.AddRange(nodesErde);

Ausnahmslos jedes in einer Strukturansicht angezeigte Element wird als TreeNode-Objekt betrachtet, das über eine eigene Auflistung ihm untergeordneter TreeNode-Objekte verfügt, die nur dann leer ist, wenn das Element das letzte in der Hierarchie ist. Mit dieser Erkenntnis können wir unser Beispiel auch beliebig tiefer strukturieren und jedem Erdteil Staaten zuordnen, die dann selbst wieder in ihrer eigenen Auflistung Städte enthalten.

Das erste Beispiel zum TreeView-Steuerelement wird jetzt in diesem Sinn ergänzt: Es werden ein paar Staaten Amerikas und Europas ergänzt, zusätzlich Städte in Deutschland und den USA.


TreeView tr = new TreeView();
tr.Location = new Point(0,0);
tr.Size = this.ClientSize;
tr.Nodes.Add("Erde");
TreeNode[] nodesErde = new TreeNode[]{ new TreeNode("Amerika"),   new TreeNode("Asien"), new TreeNode("Afrika"),   new TreeNode("Australien"), new TreeNode("Europa")};
tr.Nodes[0].Nodes.AddRange(nodesErde);
// Element 'Europa' ergänzen
TreeNode europa = tr.Nodes[0].Nodes[4];
europa.Nodes.Add("England");
europa.Nodes.Add("Frankreich");
europa.Nodes.Add("Deutschland");
europa.Nodes.Add("Italien");
// Element 'Deutschland' ergänzen
TreeNode deutschland = europa.Nodes[2];
deutschland.Nodes.Add("Bonn");
deutschland.Nodes.Add("Aachen");
deutschland.Nodes.Add("Hamburg");
deutschland.Nodes.Add("Berlin");
// Element 'Amerika' ergänzen
TreeNode amerika = tr.Nodes[0].Nodes[0];
amerika.Nodes.Add("USA");
amerika.Nodes.Add("Kanada");
amerika.Nodes.Add("Mexiko");
// Element 'USA' ergänzen
TreeNode usa = amerika.Nodes[0];
usa.Nodes.Add("Miami");
usa.Nodes.Add("New York");
usa.Nodes.Add("San Francisco");
usa.Nodes.Add("Seattle");
this.Controls.Add(tr);

Falls alle Knoten geöffnet werden, wird das Programm zu einer Anzeige wie in Abbildung 19.18 gezeigt führen. Beachten Sie, dass das TreeView-Objekt standardmäßig eine Bildlaufleiste einblendet, sobald die Länge der Liste die Höhe des Steuerelements überschreitet.

Deutlich ist am Programmcode zu erkennen, dass, je tiefer die Hierarchiestruktur geht, der Code immer unübersichtlicher wird. Zur besseren Lesbarkeit wird deshalb eine interne TreeNode-Referenz benutzt, die einen Knoten im Innern der Hierarchie referenziert.


TreeNode europa = tr.Nodes[0].Nodes[4];

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 19.18   Tiefer strukturiertes »TreeView«-Steuerelement

Die Referenz europa verweist hier auf den fünften Knoten des Stammelements, also erde. Damit reduziert sich der Code, um einen europäischen Staat hinzuzufügen, auf:


europa.Nodes.Add("England");

Ansonsten hätte die Anweisung


tr.Nodes[0].Nodes[4].Nodes.Add("England");

lauten müssen.

Beispielprogramm mit »TreeView«

Wir wollen das Erlernte auch sofort in einem kleinen Beispiel umsetzen. Aufgabe soll sein, in einem TreeView-Control sämtliche Steuerelemente der aktuellen Form anzuzeigen. Dabei soll die interne Struktur aller Containersteuerelemente ersichtlich sein. In der Strukturansicht soll jeder Elementeintrag durch ein steuerelementspezifisches Bildchen ergänzt werden, und der Beschriftungstext soll Objektname und Typ enthalten. In Abbildung 19.19 sehen Sie die Ausgabe des Beispielprogramms.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 19.19   Die Ausgabe des Beispiels »ShowControlsOnForm«


// ---------------------------------------------------------
// Beispiel: ...\Kapitel 19\ShowControlsOnForm
// ---------------------------------------------------------
public partial class Form1 : Form {
  private void btnShowControls(object sender, EventArgs e) {
    this.treeView1.Nodes.Add(this.Name);
    TreeNode[] nodesForm = new TreeNode[this.Controls.Count];
    this.treeView1.Nodes[0].ImageIndex = 5;
    this.treeView1.Nodes[0].SelectedImageIndex = 
                       this.treeView1.Nodes[0].ImageIndex;
    this.GetControls(this.Controls, this.treeView1.Nodes[0]);
  }
  private void GetControls(IList controls, TreeNode node) {
    foreach (Control control in controls) {
      int index = node.Nodes.Add(new TreeNode(control.Name));
      // das passende Image einfügen
      SetImage(node, control, index);
      if (control.Controls.Count > 0) 
        GetControls(control.Controls, node.Nodes[index]);
      }
    }
  }
  private static void SetImage(TreeNode node, Control control, int index) {
    if (control is Button) {
      node.Nodes[index].ImageIndex = 0;
      node.Nodes[index].Text = control.Name + " (Button)";
    }
    else if (control is GroupBox) {
      node.Nodes[index].ImageIndex = 1;
      node.Nodes[index].Text = control.Name + " (GroupBox)";
    }
    else if (control is RadioButton) {
      node.Nodes[index].ImageIndex = 2;
      node.Nodes[index].Text = control.Name + " (RadioButton)";
    }
    else if (control is TextBox) {
      node.Nodes[index].ImageIndex = 3;
      node.Nodes[index].Text = control.Name + " (TextBox)";
    }
    else if (control is TreeView) {
      node.Nodes[index].ImageIndex = 4;
      node.Nodes[index].Text = control.Name + " (WreeView)";
    }
    node.Nodes[index].SelectedImageIndex =  
                               node.Nodes[index].ImageIndex;
  }
}

btnShowControls ist hier der Ereignishandler der Schaltfläche mit der Beschriftung Anzeigen. Hier wird zuerst der Stammknoten erzeugt, der die Form beschreibt. Die Form ist bekanntermaßen ein Container für Steuerelemente. Aus der ControlCollection, deren Referenz uns die Eigenschaft Controls der Form liefert, ermitteln wir die Anzahl der verwalteten Steuerelemente und erzeugen ein passend großes TreeNode-Array.

Solange in der Form keine weiteren Containersteuerelemente enthalten sind, ist die Sache sehr einfach, denn dann werden automatisch alle Controls erfasst. Sollte allerdings, wie auch in unserem Beispiel., sich darunter mindestens ein Control befinden, das in einer eigenen ControlCollection die ihm zugeordneten Steuerelemente verwaltet, müssen wir auch diese Steuerelementauflistungen durchlaufen. Dazu dient die Methode GetControls, die sogar rekursiv aufgerufen werden muss, um auch eine etwaige tiefere Strukturierung zu erfassen.

SetImage hat die Aufgabe, den Typ des gefundenen Steuerelements zu ermitteln und aus der ImageList das passende Symbol festzulegen. Wir müssen wohl darauf achten, dass keine Symbolumschaltung erfolgt, wenn sich der Zustand eines Strukturelementes ändert. Daher wird in SetImage mit


node.Nodes[index].SelectedImageIndex = node.Nodes[index].ImageIndex;

der Index des ausgewählten Zustands gleich dem des nicht ausgewählten gesetzt.


Galileo Computing

19.13.2 Eigenschaften des »TreeView«-Steuerelements  downtop

In der »normalen« Ansicht werden geschlossene Knotenpunkte durch ein »+«-Symbol gekennzeichnet, geöffnete durch »-«. Der aktuelle markierte Knoten wird farblich invertiert dargestellt. Von vielen Installationsroutinen her wissen Sie, dass Strukturansichten mit Auswahlfeldern bestückt sind, aus denen der Anwender auswählen kann. Diese können Sie auch anbieten, indem Sie die Eigenschaft CheckBoxes=true festlegen. Die Einzugsbreite der untergeordneten Knoten ist per Vorgabe 19 Pixel. Verkleinern oder vergrößern können Sie diese Angabe mit der Eigenschaft Indent.

Beabsichtigen Sie, die Darstellung optisch auch ein wenig netter zu gestalten, sollten Sie für die Knoten Bildchen in Betracht ziehen. Die Gesamtverwaltung aller Knotensymbole obliegt dem TreeView, nicht den einzelnen Knoten selbst. Verwaltet werden die Symbole von einem ImageList-Objekt, die Sie vorher der Form hinzufügen müssen und der gleichnamigen Eigenschaft des TreeView im Eigenschaftsfenster angeben. Da eine ImageList nicht sehr intuitiv ist, sollten Sie bei der Zusammenstellung der Symbole sofort berücksichtigen, dass ausgewählte und nicht ausgewählte Elemente in der Strukturansicht üblicherweise mit unterschiedlichen Bildchen gekennzeichnet werden, die alle in dieser ImageList enthalten sein müssen. Besser wäre es sicherlich gewesen, wenn uns Microsoft für jeden Zustand je eine Bildauflistung spendiert hätte.

Im TreeView können Sie auch einstellen, welches Bildchen standardmäßig für bei einem ausgewählten bzw. nicht ausgewählten Knoten angezeigt werden soll. Dazu dienen die Eigenschaften ImageIndex/IndexKey (nicht ausgewählt) und SelectedImageIndex/SelectedImageKey (ausgewählt). Die Einstellungen kommen nur in dem Fall zum Tragen, wenn einem Knoten kein spezielles Symbol zugeordnet wird.

Unter StateImageList dürfen Sie auch eine zweite ImageList angeben. Hier tragen Sie nur zwei Bildchen ein, die in den Auswahlkästchen für den Zustand »ausgewählt« und »nicht ausgewählt« stehen. Das erste Symbol kennzeichnet hier den nicht ausgewählten Zustand, das zweite den ausgewählten. Sie dürfen dieser ImageList natürlich auch noch mehr Symbole hinzufügen, um für jeden Knoten ein ganz individuelles Bildchen im Kontrollkästchen zuzuordnen. Trotzdem würde ich davon abraten, weil zu viele Symbole beim Benutzer nur zu Irritationen führen.

Das aktuell markierte Element in der Strukturansicht wird farblich in einer Breite hervorgehoben, die der Breite der Beschriftung entspricht. Sie können die farbliche Hervorhebung aber auch über die gesamte Breite der Strukturansicht spannen. Dazu dient die Eigenschaft FullRowSelect=true. Allerdings wirkt sich diese Einstellung nur dann aus, wenn ShowLines=false ist. Mit ShowLines werden die Linien zwischen den neben- und untergeordneten Elementen dargestellt, mit LineColor wird deren Farbe festgelegt.

Wenn Sorted auf true festgelegt ist, werden die TreeNode-Objekte in alphabetischer Reihenfolge nach den Werten ihrer Text-Eigenschaft sortiert. Hier muss allerdings auch darauf hingewiesen werden, dass bei einer großen Anzahl von Elementen immer die Methoden BeginUpdate und EndUpdate aufgerufen werden sollten, um Leistungseinbußen zu verhindern. Haben Sie zudem LabelEdit=true eingestellt, kann der Benutzer zur Laufzeit den Beschriftungstext ändern. Sie müssen dann die Methode Sort aufrufen, um die Elemente neu zu sortieren.

Nicht üblich ist es, in einer Strukturansicht auf die Plus-/Minusschaltflächen zu verzichten. Dennoch, wenn Sie das anstreben, können Sie diesen Effekt mit ShowPlusMinus=false erreichen. ShowRootLines steuert letztendlich die Anzeige von Linien zwischen den Stammknoten.

Damit sind noch nicht alle Möglichkeiten des TreeView erschöpft.

Wenn die HotTracking-Eigenschaft auf true festgelegt ist, wird jede Strukturknotenbezeichnung als Hyperlink dargestellt, während der Mauszeiger darüber bewegt wird. Dabei wird die Schrift unterstrichen und in Blau festgelegt. Die Darstellung wird nicht durch die Interneteinstellungen im Betriebssystem des Benutzers gesteuert, Sie können sie also nicht beeinflussen.

Manchmal muss der markierte Knoten abgerufen oder ein bestimmter Knoten ausgewählt werden. Hier hilft die Eigenschaft SelectedNode weiter, welche die Referenz des TreeNode-Objekts zurückliefert oder entgegennimmt:

Der Eigenschaft PathSeparator eines TreeView-Objekts kommt im Zusammenhang mit der Eigenschaft FullPath eines TreeNode-Objekts besondere Bedeutung zu. FullPath liefert für jeden Knoten eine Zeichenfolge zurück, in welcher der Bezeichner des Knotens mit allen seinen zum Ursprung zurückführenden Knoten verbunden wird. PathSeparator legt das Trennzeichen fest, das standardmäßig ein Backslash ist.

Damit haben Sie jetzt eine Menge Eigenschaften kennen gelernt, um die Darstellung des TreeView und der darin angezeigten Knoten zu beeinflussen. Das TreeView wartet mit noch einigen weiteren spezifischen Eigenschaften auf, denen wir uns aber erst weiter unten widmen. Fassen wir die bisherigen zunächst einmal in einer Tabelle zusammen.


Tabelle 19.14   Die Eigenschaften eines »TreeView«-Objekts

Eigenschaft Beschreibung
CheckBoxes Gibt an, ob Auswahlkästchen angezeigt werden.
FullRowSelect Gibt an, ob die farbliche Hervorhebung die gesamte Breite des TreeView umfasst.
HideSelection Entfernt die farbliche Hervorhebung des ausgewählten Knotens, wenn das TreeView nicht im Besitz des Fokus ist.
HotTracking Legt fest, ob die Strukturknotenbezeichnung als Hyperlink dargestellt wird.
ImageIndex Der Index des Bildes, das angezeigt wird, wenn der Knoten nicht ausgewählt ist und dem Knoten für diesen Fall kein spezielles Symbol zugeordnet ist.
IndexKey Der Schlüssel des Bildes, das angezeigt wird, wenn der Knoten nicht ausgewählt ist und dem Knoten für diesen Fall kein spezielles Symbol zugeordnet ist.
ImageList Die Liste aller Bildchen für die Strukturknoten.
Indent Die Einzugsbreite untergeordneter Knoten in Pixel.
LabelEdit Gibt an, ob der Anwender den Beschriftungstext der Knoten bearbeiten kann.
LineColor Legt die Farbe der knotenverbindenden Linien fest.
PathSeparator Das Zeichenfolgentrennzeichen für den Pfad, der von der Eigenschaft FullPath eines TreeNodes zurückgegeben wird.
SelectedImageIndex Der Index des Bildes, das angezeigt wird, wenn der Knoten ausgewählt ist und dem Knoten für diesen Fall kein spezielles Symbol zugeordnet ist.
SelectedImageKey Der Schlüssel des Bildes, das angezeigt wird, wenn der Knoten ausgewählt ist und dem Knoten für diesen Fall kein spezielles Symbol zugeordnet ist.
SelectedNode Liefert das aktuell ausgewählte TreeNode-Objekt zurück.
ShowLines Gibt an, ob Linien zwischen neben- bzw. untergeordneten Knoten angezeigt werden.
ShowPlusMinus Gibt an, ob Plus-/Minusschaltflächen angezeigt werden.
ShowRootLines Gibt an, ob Linien zwischen den Stammknoten angezeigt werden.
Sorted Gibt an, ob die Elemente der Strukturansicht sortiert werden können.
StateImageList Gibt das ImageList-Steuerelement an, das die beiden Bildchen enthält, die in den Auswahlboxen angezeigt werden.


Galileo Computing

19.13.3 Die Unterstützung der Entwicklungsumgebung  downtop

Weiter oben habe ich Ihnen gezeigt, wie Sie mit Programmcode die Knotenstruktur eines Steuerelements festlegen können. Baut sich die Struktur erst zur Laufzeit aufgrund bestimmter Bedingungen dynamisch auf, werden Sie um die Hardcodierung nicht herumkommen. Sollten Sie aber zur Entwicklungszeit bereits zumindest einen Teil der Knoten kennen, können Sie auf die Tools der Entwicklungsumgebung zurückgreifen, um schneller ans Ziel zu kommen.

Nachdem Sie aus der Toolbox ein TreeView-Steuerelement in die Form gezogen haben, öffnen Sie dessen Eigenschaftsfenster und markieren die Eigenschaft Nodes. Über die Schaltfläche in der Wertespalte gelangt man zu dem in der Abbildung 19.20 gezeigten Assistenten.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 19.20   Der Assistent zum Hinzufügen von »TreeNode«-Objekten

Über die Schaltfläche Stamm hinzufügen erstellt man grundsätzlich immer einen Knoten, welcher der Auflistung TreeNodeCollection des TreeView-Steuerelements zugeordnet wird. Markiert man ein beliebiges Element im Anzeigebereich und klickt auf die Schaltfläche Unterordner hinzufügen, wird zu dem ausgewählten Knoten ein neuer, untergeordneter Knoten erzeugt.

Entscheidend für den Benutzer ist die Beschriftung der Knoten. Legen Sie diese in der Eigenschaft Text fest. Sie sollten auch nicht vergessen, den TreeNode-Objekten passende Namen zu geben. Eine gute Idee der Microsoft-Entwickler war, dass Sie den Schriftstil der Beschriftung jedes einzelnen Knotens mit NodeFont beeinflussen können. Das hilft optisch bei der Orientierung in komplexen Strukturen.

Wird über die Eigenschaft ImageList des TreeView-Objekts eine Bildliste referenziert, kann vor jedem Knoten ein Symbol angegeben werden, das immer dann angezeigt wird, wenn das Element nicht ausgewählt ist. Das Bild für den ausgewählten Zustand wird unter SelectedImageIndex oder SelectedIndexKey eingestellt. Haben die beiden Eigenschaften keine individuellen Einträge, werden die Standardeinstellungen der übergeordneten TreeView übernommen. Analog stellen Sie das Bildchen für den nicht ausgewählten Zustand unter ImageIndex oder ImageKey ein.

Zum Schluss bliebe noch zu erwähnen, dass der Zustand der optionalen Kontrollkästchen mit Checked festgelegt wird.


Galileo Computing

19.13.4 Die Ereignisse des »TreeView«-Steuerelementdowntop

Die wichtigsten objektspezifischen Ereignisse hängen mit dem Aufklappen und Schließen eines Knotenpunkts zusammen. Für jede der genannten Benutzeraktionen löst das TreeView-Steuerelement jeweils zwei Ereignisse aus: eins, das auftritt, bevor die damit verbundene, sichtbare Reaktion des Knotens erfolgt (BeforeExpand bzw. BeforeCollapse), und eins zum Abschluss des Vorgangs (AfterExpand bzw. AfterCollapse).

In diesem Zusammenhang spielen auch noch drei weitere Ereignisse eine Rolle. Wird der angeklickte Knoten beim Öffnen oder Schließen gleichzeitig ausgewählt, haben wir es mit dem Ereignispaar BeforeSelect und AfterSelect zu tun. Jedoch unabhängig davon, ob ein Knotenelement beim Anklicken ausgewählt ist oder nicht, wird in jedem Fall NodeMouseClick ausgelöst.


Tabelle 19.15   Ereignisse, die mit der Knotenauswahl ausgelöst werden können

Ereignis Beschreibung
BeforeExpand Wird ausgelöst, bevor der Knoten geöffnet wird.
AfterExpand Wird ausgelöst, nachdem der Knoten geöffnet worden ist.
BeforeSelect Wird ausgelöst, bevor ein Knoten ausgewählt wird.
AfterSelect Wird ausgelöst, nachdem ein Knoten ausgewählt wurde.
BeforeCollaps Wird ausgelöst, bevor der Knoten geschlossen wird.
AfterCollaps Wird ausgelöst, nachdem der Knoten geschlossen worden ist.
NodeMouseClick Wird ausgelöst, wenn der Benutzer auf ein treeNode klickt.

BeforeExpand, BeforeSelect und BeforeCollapse übergeben dem Ereignishandler ein Objekt vom Typ TreeViewCancelEventArgs, die Ereignisse AfterExpand, AfterSelect und AfterCollapse ein Objekt vom Typ TreeViewEventArgs. Das zuerst aufgeführte Args-Objekt, dessen spezifische Eigenschaften wir uns nun in einer Tabelle ansehen wollen, unterscheidet sich nur dadurch, dass der eingeleitete Vorgang mit Cancel abgebrochen werden kann.


Tabelle 19.16   Eigenschaften eines »TreeViewCancelEventArgs«-Objekts

Eigenschaft Beschreibung
Action Ruft den Typ der Enumeration TreeViewAction ab, die das Ereignis ausgelöst hat.
Cancel Ruft einen Wert ab, der angibt, ob das Ereignis abgebrochen werden soll, oder legt diesen fest.
Node Ruft die Referenz auf den Strukturknoten ab, der aktiviert, erweitert, reduziert oder ausgewählt werden soll.

Die Action-Eigenschaft sollten wir uns noch einmal genauer ansehen. Sie ist vom Typ der Enumeration TreeViewAction und liefert uns einen Wert, aus dem die Ursache der Ereignisauslösung entnommen werden kann.


Tabelle 19.17   Konstanten der Enumeration »TreeViewAction«

Member Beschreibung
Unknown Die Aktion, die das Ereignis ausgelöst hat, ist unbekannt.
ByKeyboard Eine Tastatureingabe hat das Ereignis ausgelöst.
ByMouse Ein Mausvorgang hat das Ereignis ausgelöst.
Collapse Das Ereignis wurde durch das Zusammenklappen eines Knotens ausgelöst.
Expand Das Ereignis wurde durch das Expandieren eines Knotens ausgelöst.


Galileo Computing

19.13.5 Weitere Eigenschaften und Methoden des »TreeView«-Objekts  downtop

Die Ansicht des TreeView-Objekts wird jedes Mal aktualisiert, sobald ein Element hinzugefügt wird. Das kann zu Leistungseinbußen und zum Flackern der Anzeige führen, wenn beispielsweise in einer Schleife viele Strukturknoten hinzugefügt werden. Um das zu vermeiden, sollte man vor Beginn der Einfügeoperationen die Methode BeginUpdate aufrufen. Damit wird das Zeichnen des Steuerelements so lange unterbunden, bis die EndUpdate-Methode aufgerufen wird. Die gesamte Hierarchiestruktur des TreeView kann mit den Methoden ExpandAll und CollapseAll auch per Programmcode entweder erweitert oder reduziert werden.

Die Klasse TreeNode veröffentlicht ihrerseits Methoden, mit denen die untergeordnete Struktur eines bestimmten Knotens erweitert oder reduziert wird – ungeachtet der Tatsache, dass ein Klick des Benutzers auf das standardmäßige »+«- oder »-«-Zeichen dieselbe Reaktion des Knotens bewirkt.

In der folgenden Tabelle werden die in diesem Abschnitt aufgeführten Methoden noch einmal zusammengefasst.


Tabelle 19.18   Methoden des »TreeView«-Objekts

Eigenschaft/Methode Beschreibung
BeginUpdate Deaktiviert das Neuzeichnen des Steuerelements.
CollapseAll Reduziert alle Strukturknoten.
EndUpdate Aktiviert das Neuzeichnen des Steuerelements.
ExpandAll Expandiert alle Strukturknoten.


Galileo Computing

19.13.6 Eigenschaften und Methoden des »TreeNode«-Objekts  downtop

Bei einigen Operationen muss ein bestimmter Knoten zuerst identifiziert werden. Drei Eigenschaften unterstützen dies.


Tabelle 19.19   Eigenschaften zur Identifizierung eines »TreeNode«-Objekts

Eigenschaft Beschreibung
Index Ruft die Position des aktuellen Knotens in der Auflistung des übergeordneten Knotens ab.
Text Ruft den in der Bezeichnung des TreeNode-Objekts angezeigten Text ab oder legt diesen fest.
TreeView Ruft die Referenz des übergeordneten TreeView-Objekts ab, dem das TreeNode-Objekt zugewiesen ist.

Viele Eigenschaften dienen der Navigation durch die Hierarchie. Mit Parent kann zum Beispiel der übergeordnete Knoten bestimmt werden, mit FirstNode, LastNode, PrevNode und NextNode kann zu den nebengeordneten Knoten auf gleicher Hierarchieebene bzw. zu den untergeordneten Knoten navigiert werden. Alle geben die Referenz auf das angesteuerte TreeNode-Objekt zurück.

Die TreeNode-Klasse veröffentlicht mit IsExpanded und IsSelected zwei Eigenschaften, mit denen im Programmcode festgestellt werden kann, ob ein Knoten aktuell reduziert, erweitert oder markiert ist.


public bool IsExpanded {get;}
public bool IsSelected {get;}

Das Strukturansicht-Steuerelement unterstützt die Methoden ExpandAll und CollapseAll, um alle Knotenelemente zu erweitern oder zu reduzieren. Ein TreeNode-Objekt verfügt über ähnliche Methoden, allerdings beziehen sich diese immer auf den aktuellen Knoten.


public void Collapse();
public void Expand();
public void ExpandAll();
public void Toggle();

Mit der Methode Toggle wechselt der Knoten in den entgegengesetzten Zustand, also entweder von erweitert nach reduziert oder von reduziert nach erweitert.

In der folgenden Tabelle 19.20 werden die Eigenschaften und Methoden eines Strukturknotens noch einmal zusammengefasst.


Tabelle 19.20   Eigenschaften und Methoden des »TreeNode«-Objekts

Eigenschaft/Methode Beschreibung
Parent (Eigenschaft) Ruft das übergeordnete TreeNode-Objekt des aktuellen Strukturknotens ab.
FirstNode (Eigenschaft) Ruft das erste untergeordnete TreeNode-Objekt in der Auflistung der Strukturknoten ab.
PrevNode (Eigenschaft) Ruft das vorherige nebengeordnete TreeNode-Objekt ab.
NextNode (Eigenschaft) Ruft das nächste nebengeordnete TreeNode-Objekt ab.
LastNode (Eigenschaft) Ruft das letzte untergeordnete TreeNode-Objekt ab.
IsSelected (Eigenschaft) Ruft einen Wert ab, der angibt, ob das TreeNode-Objekt ausgewählt ist.
IsExpanded (Eigenschaft) Ruft einen Wert ab, der angibt, ob das TreeNode-Objekt erweitert ist.
Collapse (Methode) Reduziert das TreeNode-Objekt.
Expand (Methode) Erweitert das TreeNode-Objekt.
ExpandAll (Methode) Erweitert alle untergeordneten TreeNode-Objekte.
Toggle (Methode) Wechselt zwischen dem erweiterten und dem reduzierten Zustand.


Galileo Computing

19.13.7 Beispiel zum Einlesen der Verzeichnisstruktur  toptop

Wir wollen nun ein Beispiel entwickeln, das als Ergebnis die lokale Verzeichnisstruktur anzeigt. Nach dem Start sollen im TreeView-Steuerelement alle Laufwerke angezeigt werden. Dazu ist die Auflistung TreeNodeCollection des Steuerelements mit allen Laufwerksangaben zu füllen. Die erforderlichen Angaben liefert uns die statische Methode GetLogicalDrives der Klasse Directory als Zeichenfolge-Array.

Mit dieser Erkenntnis wäre ein Teil der Aufgabe schon gelöst, aber wir wollen schließlich im Strukturansicht-Steuerelement nicht nur die Laufwerksangaben sehen, sondern auch durch alle Unterverzeichnisse navigieren. Eine erste Idee könnte jetzt sein, sofort die Verzeichnisstruktur jedes Laufwerks der lokalen Maschine vollständig einzulesen. Denken Sie aber daran, wie lange die Suche nach einem bestimmten Ordner oder einer bestimmten Datei dauert. Wenn Sie Glück haben, wird das gesuchte Objekt schnell gefunden, mit etwas Pech warten Sie aber auch eine Zeitspanne, die sich im Bereich von Minuten bewegen kann. Ein ähnliches Problem hätten wir auch zu erwarten, wenn wir direkt nach dem Start die gesamte Verzeichnisstruktur in das TreeView-Objekt einlesen würden.

Das vollständige Einlesen der Verzeichnisstruktur ist also keine gute Lösung. Auf jedwedes Einlesen von Unterverzeichnissen zu verzichten, würde uns zwar die Laufwerke liefern, aber wir könnten nicht erkennen, ob diese ein untergeordnetes Verzeichnis haben, denn dann würde im reduzierten Zustand kein »+«-Zeichen auf die untergeordnete Ebene aufmerksam machen.

Wir benötigen eine Zwischenlösung, die einerseits die Informationen bereitstellt, dass ein Knoten weitere untergeordnete Knoten enthält, aber andererseits auch nicht unnötig viele Informationen einliest, die das Laufzeitverhalten negativ beeinflussen. Mit anderen Worten lesen wir optimalerweise gerade so viel von der Verzeichnisstruktur ein, dass zu jedem angezeigten Knoten gerade die ihm direkt untergeordnete Knotenebene bekannt ist.

Nach dem Anwendungsstart werden nur die Laufwerke angezeigt, nehmen wir an A:\ und C:\. Das »+«-Zeichen erscheint nur dann, wenn für diesen Knoten alle direkt untergeordneten Ordner bekannt sind, z.B. Dokumente und Einstellungen, Programme, WINNT usw. Diese Informationen müssen wir uns besorgen. Ein weitergehender Informationsstand ist in diesem Moment nicht erforderlich und würde nur zu Leistungseinbußen führen.

Expandiert der Benutzer einen Knoten durch Klicken auf das »+«-Zeichen, sind die Informationen der nachfolgend anzuzeigenden Hierarchieebene bereits eingelesen. Bevor die Strukturansicht aktualisiert wird, muss die der neu anzuzeigenden Ebene untergeordnete Hierarchieebene von der Festplatte gelesen und müssen die Informationen den entsprechenden Knoten zugeordnet werden, damit das informelle »+«-Zeichen, falls notwendig, erscheint. Auf diese Weise werden immer nur Teile der gesamten Verzeichnisstruktur eingelesen, was der Anwender im Normalfall nicht bemerkt. Dennoch wird er mit allen erforderlichen Informationen versorgt.

Abbildung
Hier klicken, um das Bild zu vergrößern

Abbildung 19.21   Das Ausgabefenster des Beispiels »Verzeichnisstruktur«

Sehen wir uns nun den Code zur Lösung der Aufgabenstellung an.


// --------------------------------------------------------------
// Beispiel: ...\Kapitel 19\Verzeichnisstruktur
// --------------------------------------------------------------
public partial class Form1 : Form  {
  private bool start = true;
  // Konstruktor
  public Form1() {
    InitializeComponent();
    // abrufen der lokalen Laufwerksangaben
    string[] drives = Directory.GetLogicalDrives();
    TreeNode node;
    foreach(string drv in drives) {
      node = treeView.Nodes.Add(drv);
      if(node.Text == "A:\\") {
        node.ImageIndex = 0;
        node.SelectedImageIndex = 0;
        continue;
      }
      // alle untergeordneten Verzeichnisse einlesen
      AllSubDirectories(node);
      // das Laufwerk C: aktivieren
      if(drv == "C:\\")
        treeView.SelectedNode = node;
    }
  }
  // Hinzufügen der untergeordneten Verzeichnisse eines 
  // bestimmten Knotens
  private void AllSubDirectories(TreeNode node) {            
    DirectoryInfo[] arrDirInfo;
    DirectoryInfo dirinfo = new DirectoryInfo(node.FullPath);
    // auftretende Fehler ignorieren
    try {
      arrDirInfo = dirinfo.GetDirectories();
    }
    catch {
      return;
    }
    foreach (DirectoryInfo info in arrDirInfo) {
      node.Nodes.Add(info.Name);
    }
  }
  // ein Knoten in der Strukturansicht soll expandiert werden
  private void treeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) {
    foreach(TreeNode node in e.Node.Nodes) {
      AllSubDirectories(node);
    }
  }
  private void treeView_AfterSelect(object sender, TreeViewEventArgs e) {
    if(e.Node.Nodes.Count == 0)
      AllSubDirectories(e.Node);
    }
  }
  ...
}

Die Methode AllSubDirectories bildet das Kernelement des Beispielprogramms und hat die Aufgabe, die übergebene TreeNode-Referenz auf untergeordnete Elemente hin zu untersuchen. Dazu wird uns die Methode GetDirectories, die auf ein DirectoryInfo-Objekt aufgerufen wird, alle notwendigen Informationen liefern. Beim Start der Anwendung müssen wir uns nur noch alle aktuell verfügbaren Laufwerke besorgen. Das passiert direkt im Anschluss an InitializeComponent im Konstruktor mit:


string[] drives = Directory.GetLogicalDrives();

Wenn alle Laufwerke zur Verfügung stehen, sollen »+«-Zeichen auf die erste Ordnerebene hinweisen. Dabei ist allerdings eine Hürde zu meistern. Das für Diskettenlaufwerke reservierte Laufwerk »A:\« sowie auch verschiedene weitere Laufwerke (zum Beispiel das für CDs) könnten bei der Suche kein Medium enthalten. Es wird dann von GetDirectories eine IOException ausgelöst, die behandelt werden muss. Handelt es sich um das Diskettenlaufwerk, wird vor der Ausnahme vom System außerdem auch noch ein Meldungsfenster angezeigt, das mit Abbrechen oder Weiter geschlossen werden kann. Dieses Meldungsfenster sollten wir beim Start der Anwendung unbedingt vermeiden, da es zu Irritationen führt.

Nachdem wir alle logischen Laufwerke im Konstruktor eingelesen haben, werden deren Ordner eingelesen. Nur das Diskettenlaufwerk ist davon ausgeschlossen. Allerdings weisen wir diesem Laufwerk ein anderes Symbol für den ausgewählten und nicht ausgewählten Zustand zu.

In AllSubDirectories ist uns die Eigenschaft FullPath des TreeNode-Objekts behilflich, den kompletten Pfad vom Stammknoten bis zum aktuellen Strukturknoten zu beschreiben. Mit


DirectoryInfo dirinfo = new DirectoryInfo(node.FullPath);

besorgen wir uns auf Basis der Pfadangabe ein Verzeichnisobjekt vom Typ Directory. Dieses liefert unter Aufruf der Methode GetDirectories alle Unterverzeichnisse als String-Array:


DirectoryInfo[] arrDirInfo;
arrDirInfo = dirinfo.GetDirectories();

Wir müssen diese Anweisung allerdings durch eine Ausnahmebehandlung absichern, denn wenn beispielsweise im Diskettenlaufwerk keine Diskette eingelegt ist, wird eine Exception ausgelöst, die behandelt werden muss.

Mit


foreach(DirectoryInfo info in arrDirInfo){
  node.Nodes.Add(info.Name);
}

wird schließlich jedes Verzeichnis des Arrays arrDirInfo durchlaufen und der TreeNodeCollection des Knotens, also des Verzeichnisses, hinzugefügt, der als Parameter dem Methodenaufruf übergeben worden ist.

Damit ist die Methode AddSubDirectories fertig. Sie ist dabei so universell, dass sie nicht nur aus dem Konstruktor der Form heraus aufgerufen wird, sondern jedes Mal, bevor der Anwender einen Verzeichniseintrag öffnet, also im Ereignis BeforeExpand.

Zum Schluss müssen wir noch sicherstellen, dass bei einem Klick auf das Symbol eines logischen Laufwerks auch dann die Methode AllSubDirectories ausgeführt wird, wenn kein Zeichen zum Expandieren des Strukturknotens vorhanden ist. Das ist der Fall, wenn beim Start der Anwendung kein Medium eingelegt ist. Der Ereignishandler von BeforeExpand wird dann nicht ausgelöst, weil es nichts zu expandieren gibt. Aus diesem Grund wird das Ereignis AfterSelect behandelt, das auftritt, wenn ein Strukturknoten angeklickt wird. Um nicht bei jedem expansionsfähigen Knoten die Routine unnötigerweise doppelt auszuführen, wird im Ereignishandler der ereignisauslösende Knoten daraufhin untersucht, ob seine Auflistung leer ist. Nur wenn die Auflistung leer ist, wird AllSubDirectories ausgeführt.

 << zurück
  
  Zum Katalog
Zum Katalog: Visual C# 2005
Visual C# 2005
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Fortgeschrittene Programmierung mit Visual C# 2005






 Fortgeschrittene
 Programmierung
 mit Visual C# 2005


Zum Katalog: Einstieg in Visual C# 2005






 Einstieg in
 Visual C# 2005


Zum Katalog: Einstieg in Visual Basic 2005






 Einstieg in
 Visual Basic 2005


Zum Katalog: Visual Basic 2005






 Visual Basic 2005


Zum Katalog: Java ist auch eine Insel






 Java ist auch eine
 Insel


Zum Katalog: Konzepte und Lösungen für Microsoft-Netzwerke






 Konzepte und
 Lösungen für
 Microsoft-Netzwerke


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo








Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de