## 19.9 WPF-Listenelemente – ItemControls Eine Reihe verschiedener WPF-Steuerelemente sind in der Lage, Listen anzuzeigen. Zu diesen Controls werden unter anderem die ListBox, die ComboBox, das TabControl, die ListView und das TreeView-Control gerechnet. Die von diesen Controls dargestellten Listenelemente lassen sich in zwei Gruppen kategorisieren: ItemControls HeaderedItemControls Listensteuerelemente, die Listenelemente der Gruppe der ItemControls anzeigen, zeichnen sich durch die Eigenschaft Items aus. Diese Eigenschaft gewährleistet den Zugriff auf die einzelnen Elemente der Liste, der über den Index des Elements erfolgen kann. Typische Vertreter für Steuerelemente, die ItemControls aufnehmen, sind die ListBox und die ComboBox. Je nach Typ des anzeigenden Controls werden die Listenelemente durch besondere Klassen beschrieben. Im Fall einer ListBox handelt es sich um ListBoxItem, bei der ComboBox sind es Elemente vom Typ ComboBoxItem. Von der Klasse ItemControls ist die Klasse HeaderedItemControls abgeleitet. Es ist die Eigenschaft Header, die Elemente dieses Typs auszeichnet. Mit der Eigenschaft Header kann einem Element ein »Titel« zugewiesen werden, der einer Spalte zugeordnet wird. Steuerelemente der Gruppe der HeaderedItemControls bilden somit keine einfache lineare, sondern eine hierarchische Struktur ab. Typische Vertreter dieser Gruppe sind die Klassen MenuItem, TreeView und auch ToolBar. ### 19.9.1 Das Steuerelement »ListBox« ListBoxen bieten eine Liste von möglichen Auswahlalternativen an, aus denen der Anwender eine oder auch mehrere wählen kann. Per Vorgabe gestattet eine ListBox nur die Einfachauswahl. Damit auch die Auswahl mehrerer Einträge möglich ist, müssen Sie die Eigenschaft SelectionMode auf Multiple oder Extended festlegen. Multiple gestattet dabei die Auswahl durch einen einfachen Klick. Bei der Einstellung Extended muss der Anwender beim Anklicken des Listenelements die -Taste gedrückt halten. Um eine klassische ListBox zu erzeugen, verwenden Sie für jedes Listenelement die Klasse ListBoxItem.
    <ListBox Name="ListBox1">
      <ListBoxItem>Peter</ListBoxItem>
      <ListBoxItem>Franz</ListBoxItem>
      <ListBoxItem>Rolf</ListBoxItem>
      <ListBoxItem>Hans-Günther</ListBoxItem>
    </ListBox>
Sie können der ListBox sowohl im XAML-Code als auch in der Code-Behind-Datei Listenelemente hinzufügen. Alle Listenelemente werden in der ListBox von einer Collection verwaltet, deren Referenz die Eigenschaft Items liefert. Durch Aufruf der Methode Add fügen Sie nach Bedarf Elemente hinzu:
    ListBox1.Items.Add("Beate");
    ListBox1.Items.Add("Gudrun");
Damit nicht genug: Anstatt eine Liste von ListBoxItems zu definieren, können Sie auch andere Steuerelemente angeben. Im folgenden Codefragment sind beispielsweise CheckBox-Elemente hinzugefügt worden:
    <ListBox Name="ListBox1">
      <CheckBox Name="A" Margin="3">Peter</CheckBox>
      <CheckBox Name="B" Margin="3">Franz</CheckBox>
      <CheckBox Name="C" Margin="3">Rolf</CheckBox>
      <CheckBox Name="D" Margin="3">Hans-Günter</CheckBox>
    </ListBox>
Das Hinzufügen von ListBox-Einträgen ist auch mittels Programmcode möglich:
    CheckBox chk1 = new CheckBox();
    chk1.Content = "Beate";
    chk1.Margin = new Thickness(3);
    CheckBox chk2 = new CheckBox();
    chk2.Content = "Gudrun";
    chk3.Margin = new Thickness(3);
    ListBox1.Items.Add(chk1);
    ListBox1.Items.Add(chk2);
Beachten Sie bei diesem Code, dass die Eigenschaft Margin durch den Typ Thickness beschrieben wird. Hier klicken, um das Bild zu vergrößern Abbildung 19.22 ListBox mit CheckBoxen #### Zugriff auf das ausgewählte Element Das ausgewählte Element bzw. die ausgewählten Elemente werden in der Regel im Programmcode für die weiteren Operationen benutzt. Die ListBox stellt Eigenschaften bereit, die es erlauben, die entsprechenden Elemente auszuwerten.

Tabelle 19.11 Eigenschaften der ListBox (Elementauswahl)

Eigenschaft | Beschreibung
SelectedIndex | Gibt den Index des ersten Elements in der aktuellen Auswahl zurück. Ist die Auswahl leer, ist der Rückgabewert -1. Mit dieser Eigenschaft kann auch ein Element vorselektiert werden.
SelectedItem | Gibt das erste Element in der aktuellen Auswahl zurück. Ist die Auswahl leer, ist der Rückgabewert null.
SelectedItems | Ruft alle ausgewählten Elemente ab.
Möchten Sie, dass ein bestimmtes Listenelement beim Starten des Windows vorselektiert ist, verwenden Sie die Eigenschaft SelectedIndex. Da die Liste der Elemente nullbasiert ist, genügt die Anweisung
    ListBox1.SelectedIndex = 0;
um das erste Element zu markieren. Etwas schwieriger gestaltet es sich, den Inhalt eines ausgewählten Elements auszuwerten. Nehmen wir dazu den folgenden XAML-Code:
    <ListBox Name="ListBox1">
      <ListBoxItem>Frankreich</ListBoxItem>
      <ListBoxItem>Italien</ListBoxItem>
      <ListBoxItem>Polen</ListBoxItem>
      <ListBoxItem>Dänemark</ListBoxItem>
    </ListBox>
Um sich den Inhalt des ausgewählten Elements in einer MessageBox anzeigen zu lassen, ist der folgende Code notwendig:
    MessageBox.Show(((ListBoxItem)ListBox1.SelectedItem).Content.ToString());
Zuerst lassen wir uns das erste ausgewählte Element mit der Methode SelectedItem zurückgeben und konvertieren es in den Typ, der die Listenelemente beschreibt. Hier handelt es sich um ListItem. ListItem verfügt über die Eigenschaft Content, die vom Typ Object ist. Da wir aber wissen, dass es sich um eine Zeichenfolge handelt, können wir diese mit ToString abrufen. #### Auswahl mehrerer Elemente Durch Einstellen der Eigenschaft SelectionMode auf Multiple oder Extended kann der Anwender mehrere Listenelemente gleichzeitig auswählen. Um diese auszuwerten, eignet sich SelectedItems, die die Liste aller ausgewählten Elemente bereitstellt. Sie können diese Liste beispielsweise in einer foreach-Schleife durchlaufen:
    private void btnShowItems_Click(object sender, RoutedEventArgs e) {
      string items = "";
      foreach (ListBoxItem item in ListBox1.SelectedItems)
        items += item.Content +"\n";
        MessageBox.Show(items);
    }
### 19.9.2 ComboBox Die ComboBox ähnelt der oben behandelten ListBox. Der Unterschied zwischen diesen beiden Steuerelementen ist, dass die ComboBox immer nur ein Element anzeigt und somit auch nicht viel Platz in Anspruch nimmt. Per Vorgabe kann der Anwender zur Laufzeit keine neuen Elemente in die ComboBox eintragen. Möchten Sie das aber zulassen, müssen Sie die Eigenschaft IsEditable = true setzen. Mit der Eigenschaft ReadOnly legen Sie fest, ob der Inhalt der ComboBox editiert werden kann. Die Kombination beider Eigenschaften entscheidet maßgeblich über die Handhabung des Steuerelements. Stellen Sie beispielsweise beide auf True ein, kann der Anwender kein Zeichen in die ComboBox eintragen. Ändern Sie allerdings IsEditable auf False, kann der Anwender bei fokussierter ComboBox ein Zeichen an der Tastatur eingeben. Befindet sich ein Element mit dem entsprechenden Anfangsbuchstaben in der Liste der Elemente, wird dieses ausgewählt. Die einer ComboBox zugeordneten Elemente sind vom Typ ComboBoxItem:
    <ComboBox Height="20" Name="comboBox1" Width="120">
      <ComboBoxItem>Berlin</ComboBoxItem>
      <ComboBoxItem>Hamburg</ComboBoxItem>
      <ComboBoxItem>Bremen</ComboBoxItem>
      <ComboBoxItem>Düsseldorf</ComboBoxItem>
      <ComboBoxItem>Dresden</ComboBoxItem>
      <ComboBoxItem>München</ComboBoxItem>
    </ComboBox>
Um per Programmcode ein Element hinzuzufügen, rufen Sie mit Items die ItemCollection der ComboBox ab. Deren Methode Add übergeben Sie einfach den gewünschten zusätzlichen Eintrag:
    comboBox1.Items.Add("Stuttgart");
Das ausgewählte Element können Sie mit der Eigenschaft Text abrufen. Mit dieser Eigenschaft lässt sich auch festlegen, welches Listenelement nach dem Laden des Windows angezeigt werden soll. Gleichwertig können Sie mit SelectedIndex auch den Index des gewünschten Elements angeben. Nur zwei Ereignisse sind für die ComboBoxen DropDownOpened und DropDownClosed spezifisch. DropDownOpened wird beim Öffnen der Liste ausgelöst, DropDownClosed bei deren Schließen. ### 19.9.3 Das Steuerelement »ListView« Das Steuerelement ListView ähnelt nicht nur der ListBox, es ist sogar aus ListBox abgeleitet. Im Gegensatz zur ListBox kann ein ListView-Control die Einträge unterschiedlich darstellen. Was sich im ersten Moment noch positiv anhört, relativiert sich aber auch wieder, denn derzeit ist das nur mit einem GridView-Element direkt möglich. GridView ist aus ViewBase abgeleitet. Sie können auch eigene Darstellungsansichten durch das Ableiten von ViewBase ermöglichen, aber der Aufwand ist nicht unerheblich. Sehen wir uns zur Veranschaulichung den einfachen Einsatz des ListView-Controls als einspaltiges Listenfeld in einem Codefragment an (siehe auch Abbildung 19.23):
    <Grid>
      <ListView>
        <ListView.View>
          <GridView>
            <GridViewColumn Header="Name" />
          </GridView>
        </ListView.View>
        <ListViewItem>Peter Müller</ListViewItem>
        <ListViewItem>Franz Goldschmidt</ListViewItem>
        <ListViewItem>Rudi Ratlos</ListViewItem>
        <ListViewItem>Conie Serna</ListViewItem>
      </ListView>
    </Grid>
Hier klicken, um das Bild zu vergrößern Abbildung 19.23 Einfacher Einsatz des ListView-Controls Die Beschreibung der Kopfzeile wird innerhalb des GridView-Elements mit GridViewColumn vorgenommen. Das GridView-Element seinerseits ist der Eigenschaft View des ListView-Controls zugeordnet. Für einfache Einträge reicht das ListViewItem-Element vollkommen aus. #### Mehrspaltiges Listenfeld Um in einer ListView eine Tabelle darzustellen, ist die Bindung an eine Datenquelle erforderlich. Mit der Datenbindung werden wir uns in Kapitel 21, »Datenbindung«, noch näher beschäftigen, daher sei sie an dieser Stelle nicht detailliert erklärt. Bei der Datenquelle muss es sich um ein Objekt handeln, das die Schnittstelle IEnumerable implementiert. Das Datenobjekt wird der Eigenschaft ItemSource des ListView zugewiesen. Für jede Spalte ist ein GridViewColumn-Element zuständig. Wie im Beispiel zuvor gezeigt, wird mit der Eigenschaft Header die Beschriftung der Kopfzeile festgelegt. Die Eigenschaft DisplayMemberBinding bestimmt, welche Objekteigenschaft in der Spalte angezeigt wird. Das folgende Beispielprogramm soll die Vorgehensweise demonstrieren. Dazu stellen wir uns zuerst einmal eine Datenquelle zur Verfügung. Diese soll aus mehreren Person-Objekten bestehen, die auf der folgenden Klassendefinition basieren:
    class Person {
      public string Name { get; set; }
      public int Alter { get; set; }
      public string Wohnort { get; set; }
      public Person(string name, string ort, int alter) {
        Name = name;
        Alter = alter;
        Wohnort = ort;
      }
    }
Eine Methode erzeugt mehrere Person-Objekte und liefert als Rückgabewert ein Objekt vom Typ List<Person> an den Aufrufer. Das ist die Liste, die uns als Datenquelle dienen soll.
    private List<Person> CreatePersonListe() {
      List<Person> liste = new List<Person>();
      liste.Add(new Person("Müller", "Bonn", 56));
      ...
      return liste;
    }
Für die Bindung der Datenquelle an die Eigenschaft ItemSource eignet sich der Konstruktor des Window-Objekts. Das ListView-Objekt soll den Namen lstView haben.
    public MainWindow() {
      InitializeComponent();
      lstView.ItemsSource = CreatePersonListe();
    }
Jetzt müssen wir nur noch den XAML-Code schreiben. Die Ausgabe des Beispiels sehen Sie in Abbildung 19.24.
    // ------------------------------------------------------------------
    // Beispiel: ...\Kapitel 19\ListViewSample
    // ------------------------------------------------------------------
    <Grid>
      <ListView Name="lstView">
        <ListView.View>
          <GridView>
            <GridView.Columns>
              <GridViewColumn Header="Name" Width="100"
                              DisplayMemberBinding="{Binding Path=Name}" />
              <GridViewColumn Header="Wohnort" Width="100"
                              DisplayMemberBinding="{Binding Path=Wohnort}" />
              <GridViewColumn Header="Alter" Width="80"
                              DisplayMemberBinding="{Binding Path=Alter}" />
            </GridView.Columns>
          </GridView>
        </ListView.View>
      </ListView>
    </Grid>
Hier klicken, um das Bild zu vergrößern Abbildung 19.24 Ausgabe des Beispielprogramms »ListViewSample« ### 19.9.4 Das Steuerelement »TreeView« Mit diesem Steuerelement lassen sich Daten in hierarchischer Struktur darstellen. Sie kennen dieses Steuerelement, denn es wird auch im Windows-Explorer auf der linken Seite benutzt, um die Ordnerhierarchie dazustellen. Bei den Elementen eines TreeView-Controls handelt es sich nicht um eine lineare Liste, da jedes Element selbst wieder eine Liste untergeordneter Elemente haben kann. Die Elemente werden durch den Typ TreeViewItem beschrieben. Die Eigenschaft Header dient zur Anzeige, ist selbst aber vom Typ Object. Die Eigenschaft Content gibt den Inhalt an. Der folgende Code zeigt, wie die Elemente ineinander verschachtelt werden. In Abbildung 19.25 ist die Ausgabe des Codes zu sehen, wobei alle Knoten geöffnet sind.
    <Grid>
      <TreeView Name="treeView1">
        <TreeViewItem Header="Asien">
          <TreeViewItem Header="China" />
          <TreeViewItem Header="Vietnam" />
          <TreeViewItem Header="Philippinen" />
        </TreeViewItem>
        <TreeViewItem Header="Europa">
          <TreeViewItem Header="Deutschland">
            <TreeViewItem Header="NRW" />
            <TreeViewItem Header="Hessen" />
          </TreeViewItem>
          <TreeViewItem Header="Italien" />
          <TreeViewItem Header="Österreich" />
        </TreeViewItem>
      </TreeView>
    </Grid>
Hier klicken, um das Bild zu vergrößern Abbildung 19.25 Das TreeView-Steuerelement ### 19.9.5 Das Steuerelement »TabControl« In vielen Anwendungen werden gruppierte Inhalte durch TabControl-Steuerelemente dargestellt. Das entsprechende WPF-Steuerelement ist erstaunlich einfach zu erstellen. Jede Registerkarte wird durch ein TabItem-Element beschrieben. Die Beschriftung wird mit der Eigenschaft Header festgelegt. Zur Darstellung des Inhalts dient die Eigenschaft Content, die genau ein Element aufnehmen kann. Wie Sie aber wissen, kann es sich dabei um ein Container-Steuerelement handeln, sodass der Gestaltung des Registerkarteninhalts keine Grenzen gesetzt sind. Meist sind die Registerkarten oben angeordnet. Mit der Eigenschaft TabStripPlacement ist es möglich, diese auch links, rechts oder unten anzuordnen. Soll die Beschriftung dabei auch noch entsprechend gedreht werden, bietet sich die Eigenschaft LayoutTransform an, der mit RotateTransform ein Element untergeordnet wird, das den Drehwinkel im Uhrzeigersinn beschreibt. Das folgende Codefragment zeigt ein TabControl, dessen Tabs rechts angeordnet sind. Die Beschriftung der einzelnen Tabs ist um 90° gedreht.
    <Grid>
      <TabControl TabStripPlacement="Right">
        <TabItem Header="Tab 1" Height="30">
          <TabItem.LayoutTransform>
            <RotateTransform Angle="90" />
          </TabItem.LayoutTransform>
          <TabItem.Content>
            Hier steht der Inhalt der 1. Registerkarte.
          </TabItem.Content>
        </TabItem>
        <TabItem Header="Tab 2">
          <TabItem.LayoutTransform>
            <RotateTransform Angle="90" />
          </TabItem.LayoutTransform>
          <TabItem.Content>
            Hier steht der Inhalt der 2. Registerkarte.
          </TabItem.Content>
        </TabItem>
        <TabItem Header="Tab 3">
          <TabItem.LayoutTransform>
            <RotateTransform Angle="90" />
          </TabItem.LayoutTransform>
          <TabItem.Content>
            Hier steht der Inhalt der 3. Registerkarte.
          </TabItem.Content>
        </TabItem>
      </TabControl>
    </Grid>
Hier klicken, um das Bild zu vergrößern Abbildung 19.26 Das Steuerelement »TabControl« ### 19.9.6 Menüleisten Bisher haben wir uns mit den wichtigsten Steuerelementen beschäftigt, die relativ einfach zu erstellen sind. Es ist nun an der Zeit, uns mit einem etwas komplexeren Steuerelement auseinanderzusetzen – mit der Menüleiste. Die Menüleiste wird durch die Klasse Menu beschrieben, die untergeordneten Menüpunkte durch MenuItem. Trennstriche werden durch Separator beschrieben. Die Struktur eines Menüs sehen wir uns am besten an einem Beispiel an.
    <DockPanel>
      <Menu DockPanel.Dock="Top" Name="mnuMenu">
        <MenuItem Header="_Datei">
          <MenuItem Header="_Neu" />
          <MenuItem Header="_Öffnen" />
          <Separator />
          <MenuItem Header="_Speichern" />
          <MenuItem Header="Speichern _unter ..." />
          <Separator />
          <MenuItem Header="_Senden an">
            <MenuItem Header="_Mail" />
            <MenuItem Header="_Desktop" />
          </MenuItem>
          <MenuItem Header="_Beenden" />
        </MenuItem>
        <MenuItem Header="_Bearbeiten" />
        <MenuItem Header="_Hilfe" />
      </Menu>
      <StackPanel>
      </StackPanel>
    </DockPanel>
Menüs werden meistens oben am Rand des Arbeitsbereichs des Windows verankert. Dazu bietet sich das DockPanel an. Im Menü selbst wird die Eigenschaft DockPanel.Dock auf Top festgelegt. Um den verbleibenden Bereich auszufüllen, ist im Code nach Menu noch ein StackPanel aufgeführt. In der ersten dem Menu-Steuerelement untergeordneten Ebene sind alle Elemente des Hauptmenüs aufgeführt. Diese sind vom Typ MenuItem. Jedes MenuItem kann für sich wieder eine ihm selbst untergeordnete Ebene eröffnen. Eingeschlossen wird eine Ebene jeweils zwischen dem öffnenden und dem schließenden Tag von MenuItem. Die Beschriftung der Menüelemente erfolgt mit der Eigenschaft Header. Wie bei anderen Steuerelementen auch kann mit einem Unterstrich ein Access-Key festgelegt werden. In Abbildung 19.27 sehen Sie die Ausgabe des XAML-Codes. Hier klicken, um das Bild zu vergrößern Abbildung 19.27 Ein Menü mit Untermenü in einem »Window« Zur Programmierung eines Menüelements ist nicht viel zu sagen. Hier handelt es sich wieder um das Ereignis Click, das ausgelöst wird, wenn ein Anwender auf das Menüelement klickt. #### Weitere Möglichkeiten der Menüleiste Die Klasse MenuItem stellt mit vielen Eigenschaften Möglichkeiten zur Verfügung, um Einfluss auf das Layout auszuüben. Vier davon sollen an dieser Stelle vorgestellt werden.

Tabelle 19.12 Eigenschaften der Klasse »MenuItem«

Eigenschaft | Beschreibung
Icon | Legt das Symbol fest, das in einem MenuItem angezeigt wird.
IsCheckable | Gibt an, ob ein MenuItem aktiviert werden kann.
IsChecked | Gibt an, ob das MenuItem aktiviert ist.
InputGestureText | Beschreibt die Tastenkombination.
#### Symbole anzeigen Um einem Menüelement ein Symbol zuzuordnen, können Sie über die Eigenschaft Icon ein Bild zuordnen. Benutzen Sie dazu ein Image-Element, und geben Sie dessen Attribut Source die Position zu einer Bilddatei an. Im folgenden Codeabschnitt sehen Sie die Ergänzung der oben gezeigten Menüleiste um zwei Symbole:
    <DockPanel>
      <Menu DockPanel.Dock="Top" Name="mnuMenu">
        <MenuItem Header="_Datei">
          <MenuItem Header="_Neu" />
          <MenuItem Header="_Öffnen">
            <MenuItem.Icon>
              <Image Source="Images/openHS.png" />
            </MenuItem.Icon>
          </MenuItem>
          <Separator />
          <MenuItem Header="_Speichern">
            <MenuItem.Icon>
              <Image Source="Images/saveHS.png" />
            </MenuItem.Icon>
          </MenuItem>
    ...
#### Tastenkürzel Tastenkürzel mit der -Taste werden durch einen Unterstrich kenntlich gemacht. Um einen Shortcut zu verwenden, müssen Sie diese Angabe über die Eigenschaft InputGestureText zuweisen:
    <MenuItem Header="_Öffnen" InputGestureText="Strg+O">
      <MenuItem.Icon>
        <Image Source="Images/openHS.png" />
      </MenuItem.Icon>
    </MenuItem>
Hier klicken, um das Bild zu vergrößern Abbildung 19.28 Untermenü mit Symbolen und Shortcuts #### Aktivierbare Menüelemente Manche Menüelemente sind Ein/Aus-Schaltern ähnlich. Sie signalisieren ihren augenblicklichen Zustand durch ein Häkchen. Die Voraussetzung für dieses Verhalten in einem WPF-Menü wird durch die Eigenschaft IsCheckable geschaffen. Mit IsChecked können Sie darüber hinaus festlegen, ob die Option des Menüelements ausgewählt ist oder nicht.
    <MenuItem Header="Schriftstil">
      <MenuItem Header="Fett" IsCheckable="True" IsChecked="True" />
      <MenuItem Header="Kursiv" IsCheckable="True" IsChecked="False" />
    </MenuItem>
Um ein Menüelement zu aktivieren bzw. zu deaktivieren, dient die Eigenschaft IsEnabled. Legen Sie diese auf False fest, um das Menüelement zu deaktivieren.
Hinweis
Den Code zu der hier gezeigten Menüleiste finden Sie auf der Buch-DVD unter ...\Beispiele\Kapitel 19\Menüleiste.
### 19.9.7 Kontextmenüs Kontextmenüs ähneln der eben vorgestellten Menüleiste. Im einfachsten Fall wird ein Kontextmenü direkt einem Steuerelement zugeordnet. Die Zuordnung erfolgt mit der Eigenschaft ContextMenu des betreffenden Steuerelements. Im folgenden Beispiel wird das Kontextmenü eines Buttons entwickelt:
    <Button Name="Button1" Height="25" Content="Kontextdemo">
      <Button.ContextMenu>
        <ContextMenu>
          <MenuItem Name="cMenu1" Header="Kopieren" />
          <MenuItem Name="cMenu2" Header="Ausschneiden" />
          <MenuItem Name="cMenu3" Header="Einfügen" />
        </ContextMenu>
      </Button.ContextMenu>
    </Button>
Jedes Menüelement wird, wie auch bei der Menüleiste, durch ein Objekt vom Typ MenuItem beschrieben. Mit der Eigenschaft Header wird die Beschriftung festgelegt. Häufig wird ein Kontextmenü von mehreren Steuerelementen gleichermaßen benutzt. Sie sollten die Definition des Kontextmenüs dann an einem allgemeinen Ort beschreiben. Hier bietet sich der Resources-Abschnitt des Window oder der Anwendung an. Um ContextMenu eindeutig einem bestimmten Steuerelement zuordnen zu können, muss ein key festgelegt werden, über den das Steuerelement sein zugeordnetes ContextMenu-Element identifizieren kann.
    <Window ...>
      <Window.Resources>
        <ContextMenu x:Key="contextMenu1">
          <MenuItem Header="_Ausschneiden">
            <MenuItem.Icon>
              <Image Source="Images/CutHS.png" Height="16" Width="16" />
            </MenuItem.Icon>
          </MenuItem>
          <MenuItem Header="_Kopieren">
            <MenuItem.Icon>
              <Image Source="Images/CopyHS.png" Height="16" Width="16" />
            </MenuItem.Icon>
          </MenuItem>
          <MenuItem Header="_Einfügen" Click="Event_EditPaste">
            <MenuItem.Icon>
              <Image Source="Images/PasteHS.png" Height="16" Width="16" />
            </MenuItem.Icon>
          </MenuItem>
      </ContextMenu>
    </Window.Resources>
Die Zuordnung des im Resources-Abschnitt definierten Kontextmenüs erfolgt durch Zuweisung als statische Ressource an die Eigenschaft ContextMenu des Steuerelements. Im nächsten Kapitel werden die Ressourcen thematisiert, sodass an dieser Stelle keine nähere Erklärung folgt. Das Kontextmenü kann mithilfe der Klasse ContextMenuService hinsichtlich Verhalten, Positionierung und Layout beeinflusst werden. Die Eigenschaft HasDropShadow legt beispielsweise fest, ob das Kontextmenü einen Schatteneffekt zeigen soll, und Placement bestimmt, wo das Kontextmenü erscheinen soll. Mit HorizontalOffset und VerticalOffset können Sie festlegen, wo das Kontextmenü relativ zu seinem Steuerelement angezeigt werden soll. Der folgende XAML-Code zeigt die Einbindung des im Resources-Abschnitt definierten Kontextmenüs. Hier wird eine TextBox als Elternelement festgelegt und zudem demonstriert, wie ContextMenuService zur spezifischen Beschreibung eingesetzt wird.
    <DockPanel>
      <TextBox ContextMenu="{StaticResource ResourceKey=contextMenu1}"
               ContextMenuService.HasDropShadow="True"
               ContextMenuService.Placement="Mouse" />
    </DockPanel>
### 19.9.8 Symbolleisten Auch wenn es zunächst den Anschein haben mag, dass Symbolleisten zu den komplexen WPF-Steuerelementen zu rechnen sind, ist dem nicht so. Eigentlich handelt es sich dabei nur um einen Container, der andere Controls beherbergt. Symbolleisten werden durch das Element ToolBar beschrieben. Eine ToolBar kann beliebige andere Steuerelemente aufnehmen und darstellen, aber in der Regel wird es sich dabei um Elemente vom Typ Button handeln. Üblicherweise wird eine Symbolleiste unterhalb der Menüleiste angedockt. Als Container wird daher ein DockPanel eingesetzt, das Menu als erstes Element oben angedockt, und danach folgt die Symbolleiste.
    <DockPanel>
      <Menu DockPanel.Dock="Top" Name="mnuMenu">
      </Menu>
      <ToolBar DockPanel.Dock="Top" Height="30">
        <Button>
          <Image Source="Images/openHS.png" />
        </Button>
        <Button>
          <Image Source="Images/saveHS.png" />
        </Button>
        <Separator />
        <ComboBox Width="80" SelectedIndex="0">
          <ComboBoxItem>Arial</ComboBoxItem>
          <ComboBoxItem>Courier</ComboBoxItem>
          <ComboBoxItem>Windings</ComboBoxItem>
        </ComboBox>
      </ToolBar>
        <StackPanel>
        </StackPanel>
    </DockPanel>
Beim Verkleinern des Fensters könnte es passieren, dass die Fensterbreite nicht mehr ausreicht, um alle in einer ToolBar enthaltenen Komponenten anzuzeigen. Es wird dann ein Überlaufbereich erzeugt, an dessen Ende eine Schaltfläche mit einem Pfeil angezeigt wird. Über diese Schaltfläche lässt sich ein Menü aufklappen, in dem die nicht mehr darstellbaren Elemente angezeigt werden können. Einzelnen Steuerelementen kann das Überlaufverhalten vorgeschrieben werden. Dazu wird der zugeordneten Eigenschaft OverflowMode ein Wert der gleichnamigen Enumeration übergeben.

Tabelle 19.13 Mitglieder der Enumeration »OverflowMode«

Member | Beschreibung
Always | Das Steuerelement wird immer im Überlaufbereich angezeigt.
AsNeeded | Das Steuerelement wird bei Bedarf im Überlaufbereich angezeigt.
Never | Das Steuerelement wird nie im Überlaufbereich angezeigt.
Der folgende Code beschreibt eine Symbolleiste mit drei ComboBoxen. Jeder ist eine andere Einstellung der Eigenschaft OverflowMode zugewiesen.
    <ToolBar Height="30">
      <Button>
        <Image Source="Images/openHS.png" />
      </Button>
      <Button>
        <Image Source="Images/saveHS.png" />
      </Button>
      <Separator />
      <ComboBox Width="80" SelectedIndex="0"
                ToolBar.OverflowMode="Always">
        <ComboBoxItem>Arial</ComboBoxItem>
        <ComboBoxItem>Courier</ComboBoxItem>
        <ComboBoxItem>Windings</ComboBoxItem>
      </ComboBox>
      <ComboBox Width="80" SelectedIndex="0"
                ToolBar.OverflowMode="AsNeeded">
        <ComboBoxItem>Bonn</ComboBoxItem>
        <ComboBoxItem>München</ComboBoxItem>
        <ComboBoxItem>Nürnberg</ComboBoxItem>
      </ComboBox>
      <ComboBox Width="80" SelectedIndex="0"
                ToolBar.OverflowMode="Never">
        <ComboBoxItem>Test1</ComboBoxItem>
        <ComboBoxItem>Test2</ComboBoxItem>
        <ComboBoxItem>Test3</ComboBoxItem>
      </ComboBox>
    </ToolBar>
In Abbildung 19.29 sind die Auswirkungen deutlich zu sehen. Das Kombinationslistenfeld mit der Einstellung OverflowMode=Always ist auch dann nur über die Dropdown-Schaltfläche in der Symbolleiste zu erreichen, wenn die Breite der Form eigentlich zur Darstellung ausreichen würde. Wird die Fensterbreite verringert, wird nur noch die ComboBox in der Symbolleiste angezeigt, deren Einstellung OverflowMode=Never lautet. Hier klicken, um das Bild zu vergrößern Abbildung 19.29 Der Einfluss der Eigenschaft »OverflowMode« #### Positionieren mit der Komponente »ToolBarTray« Möchten Sie mehrere ToolBars in einer Form anzeigen, bietet sich die Komponente ToolBarTray an. Dabei handelt es sich um einen Container, der das Positionieren aller enthaltenen ToolBars steuert. Mit einer ToolBarTray-Komponente wird es möglich, Symbolleisten hintereinander oder in mehreren Reihen anzuzeigen und mittels Drag&Drop zu verschieben. Zu diesem Zweck stellt das ToolBar-Steuerelement mit Band und BandIndex zwei Eigenschaften zur Verfügung, die sich auf die Positionierung im ToolBarTray auswirken. Mit Band geben Sie an, in welcher Zeile die ToolBar erscheinen soll. Mit BandIndex legen Sie deren Position innerhalb der Zeile fest, wenn die Zeile von mehreren ToolBars in Anspruch genommen wird.
    <ToolBarTray DockPanel.Dock="Top" IsLocked="False">
      <ToolBar Height="30" Band="0" BandIndex="0">
        ...
      </ToolBar>
      <ToolBar Height="30" Band="0" BandIndex="1" >
        ...
      </ToolBar>
      <ToolBar Height="30" Band="1" Band="0">
        ...
      </ToolBar>
      <ToolBar Height="30" Band="1" BandIndex="1" >
        ...
      </ToolBar>
    </ToolBarTray>
Die Einstellungen wirken sich auf die Darstellung der ToolBars nach dem Starten des Fensters aus. Zur Laufzeit kann der Anwender die Position nach Belieben mittels Drag&Drop verändern. Hier klicken, um das Bild zu vergrößern Abbildung 19.30 Zwei Symbolleisten in der Komponente »ToolBarTray« ### 19.9.9 Die Statusleiste Die meist unten im Window angezeigten Statusleisten informieren den Anwender über den Zustand des laufenden Programms. WPF stellt Ihnen mit StatusBar eine Komponente zur Verfügung, mit der Sie das realisieren können. Sie können in die StatusBar beliebige Komponenten einfügen, z. B. TextBox oder Label. Besser ist es allerdings, stattdessen mit StatusBarItem-Elementen Bereiche zu definieren, in denen die Komponenten eingebettet sind. Das ermöglicht es Ihnen, die Ausrichtung der Komponenten einfach zu gestalten. Dazu bietet sich die Eigenschaft HorizontalAlignment oder auch VerticalAlignment an.
    <DockPanel>
      <Menu DockPanel.Dock="Top" Name="mnuMenu">
      ...
      </Menu>
      <ToolBarTray DockPanel.Dock="Top" IsLocked="False">
        <ToolBar Height="30" BandIndex="0" Band="0">
          ...
        </ToolBar>
      </ToolBarTray>
      <StatusBar DockPanel.Dock="Bottom" Height="30">
        <Button Width="80">Start</Button>
        <Label>Suchen:</Label>
        <StatusBarItem Width="100"
               HorizontalContentAlignment="Stretch">
         <TextBox>Suchbegriff</TextBox>
        </StatusBarItem>
        <Separator />
        <StatusBarItem HorizontalAlignment="Right">
               Anzahl: 2</StatusBarItem>
      </StatusBar>
      <StackPanel>
      </StackPanel>
    </DockPanel>
Hier klicken, um das Bild zu vergrößern