WPF Ribbon Tutorial

Da ich gestern bereits über das Ribbon für WPF geschrieben habe nun noch ein kleines Tutorial für Einsteiger. Es zeigt die grundlegenden Eigenschaften des Robbons und ist für Einsteiger gedacht.
Zuerst erstellen wir eine neue WPF-Applikation und fügen anschließend unserem Fenster ein Grid hinzu.
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
        Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
    </Grid>
</Window>

Als nächstes folgt auch schon das eigentliche Ribbon. Um dieses überhaupt verwenden zu können muss die RibbonControlsLibrary als Referenz eingebunden werden. Fügen wir als erstes das Ribbon hinzu und geben ihm einen Namen. Danach erstellen wir ein ApplicationMenu und fügen einen Eintrag hinzu. Das ApplicationMenu ist der Blaue Button links oben. Hierbei darauf achten einen gültigen Namen für die Icons zu wählen. Die Icons können aber auch wahlweise weggelassen werden.
<ribbon:Ribbon x:Name="Ribbon">
  <ribbon:Ribbon.ApplicationMenu>
    <ribbon:RibbonApplicationMenu SmallImageSource="Images\SmallIcon.png">
      <ribbon:RibbonApplicationMenuItem Header="AppItem 1"
                                        x:Name="AppItem"
                                        ImageSource="Images\LargeIcon.png"/>
    </ribbon:RibbonApplicationMenu>
  </ribbon:Ribbon.ApplicationMenu>
</ribbon:Ribbon>


Das Menu kann dabei je nach belieben verschachtelt werden.
<ribbon:Ribbon.ApplicationMenu>
    <ribbon:RibbonApplicationMenu SmallImageSource="Images\SmalIcon.png">
        <ribbon:RibbonApplicationMenuItem Header="AppItem 1"
                                            ImageSource="Images\LargeIcon.png"/>
        <ribbon:RibbonApplicationMenuItem Header="AppItem 2"
                                            ImageSource="Images\LargeIcon.png">
            <ribbon:RibbonApplicationMenuItem Header="AppItem 2.1"
                                                ImageSource="Images\LargeIcon.png"/>
            <ribbon:RibbonApplicationMenuItem Header="AppItem 2.2"
                                                ImageSource="Images\LargeIcon.png">
                <ribbon:RibbonApplicationMenuItem Header="AppItem 2.2.1"/>
            </ribbon:RibbonApplicationMenuItem>
        </ribbon:RibbonApplicationMenuItem>
        <ribbon:RibbonApplicationMenuItem Header="AppItem 3"
                                            ImageSource="Images\LargeIcon.png"/>
    </ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
Als nächstes erstellen wir ein Tab und nennen es "HomeTab". Jedes Tab kann mit Gruppen befüllt werden, die wiederum Elemente wie Buttons beinhalten. Die Gruppe nennen wir "Group1", den Button "Button1".
<ribbon:RibbonTab x:Name="HomeTab" 
                     Header="HomeTab">
  <ribbon:RibbonGroup x:Name="Group1" 
                      Header="Group1">
    <ribbon:RibbonButton x:Name="Button1"
                         LargeImageSource="Images\LargeIcon.png"
                         Label="Button1" />
  </ribbon:RibbonGroup>

</ribbon:RibbonTab>

Einzelne Tabs können zu so genannten ContextualTabGroups zusammengefasst werden. Wie der Name schon sagt dient das dazu Tabs mit dem gleichen Kontext übersichtlich zu Gruppieren. Hierfür muss eine ContextualTabGroup erstellt werden, und der Namen dieser dem RibbonTab zugewiesen werden.
<ribbon:RibbonTab x:Name="ContextTab" 
                  Header="ContextTab"
                  ContextualTabGroupHeader="ContextGroup1">
</ribbon:RibbonTab>

<ribbon:Ribbon.ContextualTabGroups>
  <ribbon:RibbonContextualTabGroup Header="ContextGroup1"
                                   Visibility="Visible"/>
</ribbon:Ribbon.ContextualTabGroups>
Jetzt fehlt nur noch die QuickAccessToolBar. Diese stellt dem Benutzer Buttons zu Verfügung, mit denen er häufige Aktionen, wie etwa das Speichern von Dokumenten, schnell ausführen kann.
<ribbon:Ribbon.QuickAccessToolBar>
  <ribbon:RibbonQuickAccessToolBar>
    <ribbon:RibbonButton x:Name="ButtonQ1"
                         SmallImageSource="Images\SmallIcon.png"
                         Label="ButtonQ1" />
  </ribbon:RibbonQuickAccessToolBar>
</ribbon:Ribbon.QuickAccessToolBar>

Das beste Feature des Ribbons ist es, dass die Titelleiste mit einbezogen wird. So spart man Platz. Damit das jedoch möglich ist, muss statt eines Window, ein RibbonWindow als Klasse für das Fenster verwendet werden. Der komplette Code ist noch einmal hier aufgeführt:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    public partial class MainWindow : Microsoft.Windows.Controls.Ribbon.RibbonWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}
<ribbon:RibbonWindow x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
        Title="MainWindow" Height="350" Width="525">
    
    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <ribbon:Ribbon x:Name="Ribbon">
            <ribbon:Ribbon.ApplicationMenu>
                <ribbon:RibbonApplicationMenu SmallImageSource="Images\LargeIcon.png">
                    <ribbon:RibbonApplicationMenuItem Header="AppItem 1"
                                                      x:Name="AppItem"
                                                      ImageSource="Images\SmallIcon.png"/>
                </ribbon:RibbonApplicationMenu>
            </ribbon:Ribbon.ApplicationMenu>

            <ribbon:RibbonTab x:Name="HomeTab" 
                              Header="HomeTab">
                <ribbon:RibbonGroup x:Name="Group1" 
                                    Header="Group1">
                    <ribbon:RibbonButton x:Name="Button1"
                                         LargeImageSource="Images\LargeIcon.png"
                                         Label="Button1" />
                </ribbon:RibbonGroup>

            </ribbon:RibbonTab>

            <ribbon:RibbonTab x:Name="ContextTab" 
                              Header="ContextTab"
                              ContextualTabGroupHeader="ContextGroup1">
            </ribbon:RibbonTab>

            <ribbon:Ribbon.ContextualTabGroups>
                <ribbon:RibbonContextualTabGroup Header="ContextGroup1"
                                                 Visibility="Visible"/>
            </ribbon:Ribbon.ContextualTabGroups>

            <ribbon:Ribbon.QuickAccessToolBar>
                  <ribbon:RibbonQuickAccessToolBar>
                        <ribbon:RibbonButton x:Name="ButtonQ1"
                                             SmallImageSource="Images\SmallIcon.png"
                                             Label="ButtonQ1" />
                  </ribbon:RibbonQuickAccessToolBar>
            </ribbon:Ribbon.QuickAccessToolBar>

        </ribbon:Ribbon>
    </Grid>
</ribbon:RibbonWindow>
Als nächstes fügen wir noch ein SplitButton hinzu. Der SplittButton dient dazu einem Button ein kleines Auswahlmenü hinzuzufügen. Das ist dabei hilfreich, wenn eine Aktionen in verschiedenen Varianten ausgeführt werden kann.Wie beispielsweise das Speichern von Dokumenten mit "Speichern" oder "Speichern unter". Der SplittButton kann dabei auf die gleiche Weise eingesetzt werden wie der normale RibbonButton.
<ribbon:RibbonSplitButton x:Name="Button1"
                                   LargeImageSource="Images\LargeIcon.png"
                                   Label="Button1">
  <ribbon:RibbonSplitButton.Items>
    <MenuItem Header="MyItem">
      <MenuItem.Icon>
        <Image Source="Images\SmallIcon.png"/>
      </MenuItem.Icon>
    </MenuItem>
  </ribbon:RibbonSplitButton.Items>
</ribbon:RibbonSplitButton>
Nun fügen wir noch einen Button in die untere Leiste unseres ApplicationMenu's ein. Einen wirklichen nutzen gibt es zwar nicht dafür, aber vielleicht kann es einmal nützlich sein diese Möglichkeit zu kennen.
Der Code sieht wie folgt aus:
<ribbon:Ribbon.ApplicationMenu>
  <ribbon:RibbonApplicationMenu SmallImageSource="Images\LargeIcon.png">
    <ribbon:RibbonApplicationMenu.FooterPaneContent>
      <ribbon:RibbonButton x:Name="Button2"
                                   SmallImageSource="Images\SmallIcon.png"
                                   Label="Button2" />
    </ribbon:RibbonApplicationMenu.FooterPaneContent>
                    
    <ribbon:RibbonApplicationMenuItem Header="AppItem 1"
                                                      x:Name="AppItem"
                                                      ImageSource="Images\SmallIcon.png">
    </ribbon:RibbonApplicationMenuItem>
  </ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
Bookmark and Share

12 Kommentare:

Martin hat gesagt…

Hi
Thanks for your tutorial.

How can you activate the contextual tab? There's no IsActive property anymore...

Thanks in advance

Martin

Flo hat gesagt…

Hi Martin

Have you tried the Visibility property?

Martin hat gesagt…

All ContextualTabs has Visibility="True", but no one is shown.

If I put all in a all tabgroups disapear.
If they're just in they were "visible" but empty and without buttons without anything.. but they seem to be there.. but empty

Maybe you did your own example?

Martin hat gesagt…

This example is not working.. nothing is shown










This works:






But it's only shown as normal tab (as expected) without contextual title in title bar.

As you can see I'm binding the Visibility to a property - that is set correctly. What can I do?

(hope the xaml is shown in my comment... )

Martin hat gesagt…

;) Hab gerade gesehen, dass du ja Deutsch schreibst (war wohl zu oft auf englischen Foren) - ich versuchs mal ohne die Klammern...

Hast du ContextualTabGroups schon getestet? Ich kriegs nicht hin (ausser ein Empty tab - ohne Header (empty) und ohne Buttons/Groups)

Tut nicht (es erscheint kein zusätzliches tab, nix):

XML-Code:

r:RibbonContextualTabGroup Name="translationsTabGroup" Visibility="{Binding TranslationsComponentIsActive, Converter={StaticResource BoolToVisibilityConverter}}"
r:RibbonTab Name="translationsTab"
Header="{lex:LocText Key=Translations, DefaultValue='Translations'}"
IsSelected="{Binding TranslationsComponentIsActive}"
r:RibbonGroup Header="{lex:LocText Key=Delete, DefaultValue='Delete'}"
r:RibbonButton Name="TranslationsDeleteLanguageCommandItem" DataContext="{Binding Path=DeleteLanguageCommand}" /
/r:RibbonGroup
/r:RibbonTab
/r:RibbonContextualTabGroup
/r:Ribbon.ContextualTabGroups

Tut (aber ohne Contextual!, also wie ein normales Tab das eingeblendet/ausgeblendet wird):

XML-Code:
r:RibbonTab Name="translationsTab"
Header="{lex:LocText Key=Translations, DefaultValue='Translations'}"
Visibility="{Binding TranslationsComponentIsActive, Converter={StaticResource BoolToVisibilityConverter}}"
IsSelected="{Binding TranslationsComponentIsActive}"
r:RibbonGroup Header="{lex:LocText Key=Delete, DefaultValue='Delete'}"
r:RibbonButton Name="TranslationsDeleteLanguageCommandItem" DataContext="{Binding Path=DeleteLanguageCommand}" /
/r:RibbonGroup
/r:RibbonTab

Siehst du den Fehler?

Das Beispiel von Microsoft ist ja zum davonlaufen... Ich hoffe, dass es auch einfacher geht...

Was noch zu sagen ist, ich hab kein Style for ContextualTabGroups oder RibbonContextualTabGroup erstellt, da die ja sowieso direkt abgefüllt werden (anders als über dataContext der Buttons)

(ps: sorry die darstellung, wenn du an den richtigen orten die spitzen Klammern wieder setzt, sollte es leserlicher sein...)

Martin hat gesagt…

Fehler gefunden - lag zwischen Stuhl und Tastatur. MS macht die Verknüpfung von einem Tab zur kontextsensitiven Gruppe über eine "ID" ContextualTabGroupHeader, welche zugleich die Beschriftung des Tabs im Title ist.
Ich frag mich nur wie man das machen soll, wenn zwei unterschiedliche contextual Tabs mit demselben Titel referenziert werden sollen...

Sorry die zuspamerei - mein Denkfehler musste ich einfach noch posten.

Flo hat gesagt…

Hallo Martin,

schön, dass Du den Fehler gefunden hast. Ich denke MS ist davon ausgegangen, dass jedes Contextual Tab einen eindeutigen Header hat. Das kann man auch, so weit ich weiß, nicht ändern.

Warenschild hat gesagt…

Sehr schönes Tutorial genauso wie das WCF Tutorial.
Nun mal eine Frage am Rande, hast du dir das Entwickeln ganz selbst beigebracht oder schon richtig gelernt in der Ausbildung zb.?

Flo hat gesagt…

In der Ausbildung hatte ich nur sps programmieren. In der Arbeit hab ich mir dann selbst CoDeSys beigebracht.
Richtig programmieren ging erst in der Uni los. Ich hab mir noch zu Schulzeiten C++ versucht selbst beizubringen, aber das war unmöglich. Da fehlte mir die Motivation.

Jan Schubert hat gesagt…

Ein Klasse Tutorial. Ich arbeite nun auch schon seit mehreren Jahren mit der Ribbon Library und habe auch schon die ein oder andere Erfahrung damit machen dürfen.
Ich habe vor kurzem auch einen kurzen Beitrag zu Ribbon Anwendungen verfasst. Den kann man hier lesen.

Anonym hat gesagt…

guide for creating custom ribbon in .net

microsoft dynamics kosten hat gesagt…

Vielen Dank für Ihr Wissen zu teilen. Sehr gutes Tutorial! Ich bin ein Studentin, und zuletzt wurde in der Technologie interessiert, so möchte ich mehr über Ribbon Library zu lernen. Ihre Erfahrung ist für mich sehr nützlich.

Kommentar veröffentlichen