WPF: Menüband

MenübandDas Menüband ist eine sehr schöne, aber auch etwas komplexere Art und Weise, ein „besseres“ Menü aufzubauen. Anwendungen, die ein solches Menüband nutzen, sind z. B. die Microsoft Office Programme (ab Microsoft Office 2007), Windows Paint (ab Windows 7) und der Windows Explorer (ab Windows 8). Dieses Menü wird auch als Ribbon (englisch für Band) oder Ribbon Menu bezeichnet. Dieses Feature ist erst ab dem .NET Framework 4.5 vollständig verfügbar. Grundsätzlich kann das Menü in verschiedenen Arten und Designs aufgebaut werden. Wir wollen hier das Office 2010 ähnliche Ribbon vorstellen, welches im .NET Framework implementiert ist. Ein vergleichbares Ribbon können wir z. B. über die Library (DLL) „Fluent Ribbon“ einbinden (Download und Infos unter: https://github.com/fluentribbon/Fluent.Ribbon).
Bevor wir mit der Entwicklung eines Programms mit Menüband beginnen, müssen wir einen Verweis auf System.Windows.Controls.Ribbon (dabei handelt es sich um den Namensraum, welche die Steuerelemente für das Menüband enthalten) erstellen. Dazu klicken wir mit der rechten Maustaste auf den Eintrag „Verweise“ des Projekts. Im Kontextmenü wählen wir „Verweis hinzufügen“. Ein neues Fenster erscheint, in welchem wir in der Navigation auf der linken Seite den Eintrag „Assemblys“ > „Framework“ wählen. Nun muss auf der rechten Seite nur noch der passende Namensraum bzw. die passende Library (DLL) gesucht und gewählt werden. Mit einem Klick auf „OK“ wird der Verweis hinzugefügt und somit im Projekt eingebunden.
Normalerweise ist es bei Programmen mit Ribbon Menu der Fall, dass die „normale“ Windows-Titelleiste durch eine zum Menüband passende Titelleiste ersetzt wird. Um dies zu erreichen, müssen wir das Root-Element Window durch RibbonWindow ersetzen. Innerhalb unseres Layout-Panels notieren wir nun das Steuerelement Ribbon. Dieses stellt uns nun verschiedene Komponenten des Menübands zur Verfügung: Anwendungsmenü (Button oben links unterhalb der Titelleiste), Titelleiste mit Schnellzugriff (Icons oben links) und Registerkarten mit Menü-Einträgen.
Um auf das Anwendungsmenü zuzugreifen, benötigen wir die Eigenschaft ApplicationMenu, welche ein Objekt der RibbonApplicationMenu-Klasse erwartet. Dem Menü können nun RibbonApplicationMenuItem-Elemente und RibbonSeparator-Elemente untergeordnet werden. Dem RibbonApplicationMenuItem-Element können wir über die Eigenschaft Header, den anzuzeigenden Text zuweisen. Die Eigenschaft ImageSource legt das [b][i]anzuzeigende Bild[/b][/i] (Icon) fest, welches links neben dem Text angezeigt wird. Des Weiteren ist es auch möglich, RibbonApplicationMenuItem-Elemente zu verschachteln.
Die Schnellzugriffleiste können wir mit Hilfe der Eigenschaft QuickAccessToolBar erstellen. Dort werden RibbonButton-Elemente untergeordnet. Diese werden wir später auch noch bei den Registerkarten als Button verwenden. Die Eigenschaft ToolTip legt den anzuzeigenden Info-Text fest, welcher angezeigt werden soll, sobald man mit der Maus darüber fährt. Die Eigenschaft SmallImageSource legt das Icon fest. Auch über die Eigenschaft LargeImageSource kann das Icon festgelegt werden, jedoch wird hierbei ein „größeres Bild“ festgelegt. Für die Schnellzugriffleiste wird lediglich die SmallImageSource-Eigenschaft benötigt, da diese hier von Bedeutung ist. LargeImageSource wird dafür jedoch bei den „großen“ Buttons in den Registerkarten benötigt.
Dem Ribbon-Element können wir über die Eigenschaft Title den Titel festlegen, welcher innerhalb der Titelleiste (rechts neben der Schnellzugriffsleiste) angezeigt wird. Um die Registerkarten für das Menü zu erstellen, müssen wir dem Ribbon-Element RibbonTab-Elemente unterordnen.
Ein RibbonTab-Element stellt eine einzelne Registerkarte dar, welcher nun einzelne Gruppen (RibbonGroup) untergeordnet werden. Eine Gruppe dient zur Gruppierung von Buttons (RibbonButton, RibbonSplitButton und RibbonToggleButton), Auswahllisten (RibbonComboBox), Kontrollkästchen (RibbonCheckBox), Auswahlkästchen (RibbonRadioButton) und Eingabefeldern (RibbonTextBox). Der RibbonGroup wird über die Eigenschaft Header, die Beschriftung zugewiesen, welche am unteren Rand der Gruppe angezeigt wird.
Dem RibbonButton können wir über die Eigenschaft Label eine Beschriftung hinzufügen, welche unterhalb des Icons angezeigt wird und dabei einen einfachen Button darstellt. Als Eigenschaft für die Zuweisung des Icon verwenden wir innerhalb eines RibbonGroup-Steuerelements LargeImageSource oder SmallImageSource je nachdem, ob wir einen großen oder kleinen Button wollen.
Der RibbonSplitButton stellt einen Button mit Unterpunkten dar. Über die XML-Struktur werden Elemente der RibbonMenuItem-Klasse untergeordnet. Bei den RibbonMenuItem-Elementen benötigen wir die Eigenschaft Header, um die Beschriftung festzulegen. Auch hier ist das Festlegen eines Icons möglich (Eigenschaft ImageSource).
Der RibbonToggleButton ist ein Button, welcher zwei Zustände kennt (gewählt und nicht gewählt). Er ist also mit der RibbonCheckBox zu vergleichen. Der Zustand kann über die Eigenschaft IsChecked abgefragt oder gesetzt werden.
Die RibbonComboBox dient zur Darstellung einer Drop-Down-Liste. Über die Eigenschaft Label legen wir die Beschriftung fest, welche links neben der Liste angezeigt wird. Dem Element wird das RibbonGallery-Element untergeordnet. Diesem Element ordnen wir das Element RibbonGalleryCategory unter, welchem wir wiederrum ein oder mehrere RibbonGalleryItem-Elemente unterordnen. Die Eigenschaft Content legt den anzuzeigenden Text für das einzelne Item fest. Die Eigenschaft SelectedValue des RibbonGallery-Elements ruft den Wert des aktuell ausgewählten Items ab oder legt diesen fest. Zusätzlich sollten wir noch die Eigenschaft SelectedValuePath und MaxColumnCount festlegen (siehe Beispiel). Durch das Setzen des Werts IsEditable auf true, erlauben wir dem Benutzer eine Texteingabe. Jedoch sind nur unsere festgelegten Werte erlaubt. Doch warum können wir der RibbonComboBox nicht einfach nur ComboBoxItem-Elemente unterordnen? Dies geht schon, jedoch haben wir hierbei weniger „Komfort“. So können wir z. B. bei den einzelnen Items mit Hilfe der RibbonGallery unterschiedliche Schriftarten verwenden, um die Auswahl verschiedener Schriftarten zu verdeutlichen.
Zur RibbonCheckBox und dem RibbonRadioButton gibt es nicht viel Weiteres zu sagen. Die Beschriftung erfolgt über die Eigenschaft Label. Auch die Zuweisung eines Icons ist hier möglich. Um eine Gruppe von RibbonRadioButton-Steuerelementen zusammenzufassen und somit diese zu gruppieren, benötigen wir die RibbonGroup (siehe Beispiel).
Viele weitere Eigenschaften und Ereignisse von den Ribbon-Steuerelementen (wie RibbonButton, RibboCheckBox etc.) sind identisch mit den dazugehörigen „normalen“ Steuerelementen. Dies kommt daher, dass z. B. der RibbonButton von der Klasse Button abgeleitet ist. So gibt es also auch bei dem RibbonButton das Click-Event. Übrigens: Auch das RibbonApplicationMenuItem-Steuerelement verfügt über ein Click-Ereignis.
Neben den teilweisen großen Schaltflächen und dem übersichtlichen Aufbau des Menüs, verfügt das Ribbon Menu über einen weiteren Vorteil. Beim Drücken der Alt-Taste können wir über verschiedene Buchstaben oder Zahlen durch die Menüs navigieren. Dafür gibt es sowohl bei den Steuerelementen RibbonApplicationMenu und RibbonApplicationMenuItem als auch RibbonTab und RibbonButton (und natürlich auch anderen Ribbon-Steuerelementen) die Eigenschaft KeyTip. Als Wert des Attributs legen wir einen Buchstaben oder auch eine Zahl fest (siehe Beispiel).

MainWindow.xaml

<RibbonWindow x:Class="CSV20.WPF_Menüband.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Menüband" Height="500" Width="700">
    <DockPanel LastChildFill="True">
        <Ribbon DockPanel.Dock="Top" Title="Menüband">
            <Ribbon.ApplicationMenu>
                <RibbonApplicationMenu KeyTip="M">
                    <RibbonApplicationMenuItem ImageSource="Images/Neu.png" Header="Neu" KeyTip="N" />
                    <RibbonApplicationMenuItem ImageSource="Images/Öffnen.png" Header="Öffnen" KeyTip="O" />
                    <RibbonApplicationMenuItem ImageSource="Images/Speichern.png" Header="Speichern" KeyTip="S">
                        <RibbonApplicationMenuItem Header="Speichern" KeyTip="S" />
                        <RibbonApplicationMenuItem Header="Speichern unter" KeyTip="U" />
                        <RibbonSeparator />
                        <RibbonApplicationMenuItem Header="Kopie speichern" KeyTip="K" />
                    </RibbonApplicationMenuItem>
                    <RibbonSeparator />
                    <RibbonApplicationMenuItem ImageSource="Images/Drucken.png" Header="Drucken" KeyTip="P" />
                    <RibbonApplicationMenuItem ImageSource="Images/Schließen.png" Header="Schließen" KeyTip="C" />
                    <RibbonSeparator />
                    <RibbonApplicationMenuItem Header="Vorlagen" KeyTip="V">
                        <RibbonApplicationMenuItem Header="leere Datei" KeyTip="L" />
                        <RibbonApplicationMenuItem Header="Einladung" KeyTip="E" />
                        <RibbonApplicationMenuItem Header="Brief" KeyTip="B" />
                    </RibbonApplicationMenuItem>
                    <RibbonSeparator />
                    <RibbonApplicationMenuItem Header="Beenden" KeyTip="E" Click="MenuExit_Click" />
                </RibbonApplicationMenu>
            </Ribbon.ApplicationMenu>
            <Ribbon.QuickAccessToolBar>
                <RibbonQuickAccessToolBar>
                    <RibbonButton ToolTip="Neu" SmallImageSource="Images/Neu.png" KeyTip="N" />
                    <RibbonButton ToolTip="Öffnen" SmallImageSource="Images/Öffnen.png" KeyTip="O" />
                    <RibbonButton ToolTip="Speichern" SmallImageSource="Images/Speichern.png" KeyTip="S" />
                </RibbonQuickAccessToolBar>
            </Ribbon.QuickAccessToolBar>
            <RibbonTab Header="Datei" KeyTip="D">
                <RibbonGroup Header="Dateizugriff">
                    <RibbonButton LargeImageSource="Images/Neu.png" Label="Neu" KeyTip="N" />
                    <RibbonButton LargeImageSource="Images/Öffnen.png" Label="Öffnen" KeyTip="O" />
                    <RibbonSplitButton LargeImageSource="Images/Speichern.png" Label="Speichern" KeyTip="S">
                        <RibbonMenuItem Header="Speichern" />
                        <RibbonMenuItem Header="Speichern unter" />
                        <RibbonSeparator />
                        <RibbonMenuItem Header="Kopie speichern" />
                    </RibbonSplitButton>
                </RibbonGroup>
                <RibbonGroup Header="Dateioperationen">
                    <RibbonButton LargeImageSource="Images/Drucken.png" Label="Drucken" KeyTip="P" />
                    <RibbonButton LargeImageSource="Images/Schließen.png" Label="Schließen" KeyTip="C" />
                </RibbonGroup>
                <RibbonGroup Header="Programmoptionen">
                    <RibbonCheckBox Label="Automatisch Speichern" KeyTip="A" IsChecked="True" />
                    <RibbonCheckBox Label="Backups anlegen" KeyTip="B" />
                </RibbonGroup>
            </RibbonTab>
            <RibbonTab Header="Formatierung" KeyTip="F">
                <RibbonGroup Header="Schrifteinstellungen">
                    <RibbonComboBox Label="Schriftart:" IsEditable="True">
                        <RibbonGallery SelectedValue="Times" SelectedValuePath="Content" MaxColumnCount="1">
                            <RibbonGalleryCategory>
                                <RibbonGalleryItem Content="Arial" FontFamily="Arial" />
                                <RibbonGalleryItem Content="Arial Black" FontFamily="Arial Black" />
                                <RibbonGalleryItem Content="Serif" FontFamily="Serif" />
                                <RibbonGalleryItem Content="Sans-Serif" FontFamily="Sans-Serif" />
                                <RibbonGalleryItem Content="Times" FontFamily="Times" />
                                <RibbonGalleryItem Content="Times New Roman" FontFamily="Times New Roman" />
                            </RibbonGalleryCategory>
                        </RibbonGallery>
                    </RibbonComboBox>
                    <RibbonComboBox Label="Schriftgröße" IsEditable="True">
                        <RibbonGallery SelectedValue="10" SelectedValuePath="Content" MaxColumnCount="1">
                            <RibbonGalleryCategory>
                                <RibbonGalleryItem Content="8" FontSize="8" />
                                <RibbonGalleryItem Content="10" FontSize="10" />
                                <RibbonGalleryItem Content="12" FontSize="12" />
                                <RibbonGalleryItem Content="14" FontSize="14" />
                                <RibbonGalleryItem Content="16" FontSize="16" />
                                <RibbonGalleryItem Content="18" FontSize="18" />
                            </RibbonGalleryCategory>
                        </RibbonGallery>
                    </RibbonComboBox>
                </RibbonGroup>
                <RibbonGroup Header="Schriftoptionen">
                    <RibbonToggleButton Label="Fett" SmallImageSource="Images/Fett.png" KeyTip="F" />
                    <RibbonToggleButton Label="Kursiv"  SmallImageSource="Images/Kursiv.png" KeyTip="K" />
                </RibbonGroup>
                <RibbonGroup Header="Farbe">
                    <RibbonButton LargeImageSource="Images/Farbe.png" Label="Vordergrund" KeyTip="V" />
                    <RibbonButton LargeImageSource="Images/Farbe.png" Label="Hintergrund" KeyTip="H" />
                </RibbonGroup>
                <RibbonGroup Header="Seitengröße">
                    <RibbonRadioButton SmallImageSource="Images/Seite.png" Label="DIN A3" KeyTip="3" />
                    <RibbonRadioButton SmallImageSource="Images/Seite.png" Label="DIN A4" KeyTip="4" IsChecked="True" />
                    <RibbonRadioButton SmallImageSource="Images/Seite.png" Label="DIN A5" KeyTip="5" />
                </RibbonGroup>
                <RibbonGroup Header="Seitenformat">
                    <RibbonRadioButton SmallImageSource="Images/Seite.png" Label="Hochformat" IsChecked="True" />
                    <RibbonRadioButton SmallImageSource="Images/Seite.png" Label="Querformat" />
                </RibbonGroup>
            </RibbonTab>
        </Ribbon>
        <Grid>
            <!-- Hier kommt der eigentliche Fensterinhalt! -->
        </Grid>
    </DockPanel>
</RibbonWindow>

MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls.Ribbon;

namespace CSV20.WPF_Menüband
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : RibbonWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void MenuExit_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }
    }
}
Download

LinksRechts