Home » Programming » WPF » WPF Ribbon » WPF Ribbon (CTP) – Part 2 – Adding tabs and groups

WPF Ribbon (CTP) – Part 2 – Adding tabs and groups

Continuing the application from the previous tutorial, we will add tabs and groups on them.

Entire Tutorial:

Summary

  • Common Properties for the Ribbon Controls
  • Step 1: Adding Tabs
    • From XAML
    • From Code-Behind
    • RibbonTab’s Properties
    • Why some properties seem to have no visual effect?
    • Issues
  • Step 2: Adding Groups
    • From XAML
    • From Code-Behind
    • RibbonGroup’s Properties
    • Issues

Common Properties for the Ribbon Controls

All the controls that can be added on the Ribbon Groups are derived from the IRibbonControl interface. This interface is empty, but assures that you can only add certain controls on the ribbon.
Extending, the RibbonTab, RibbonGroup and any other provided ribbon control (such as RibbonButton, RibbonTextBox, RibbonSplitButton etc.) derive from the System.Windows.Controls.Control class, which allows them to have common properties, such as (of course, the base properties are a lot more, I just specified some of the most used ones):

  • ActualHeight – the rendered height of the control; this is the real height of the control
  • ActualWidth – the rendered width of the control; this is the real width of the control
  • Background – the Brush used to color the background; WPF provides the following concrete classes: SolidColorBrush, GradientColorBrush, RadialGradientBrush, ImageBrush, VisualBrush, DrawingBrush, and also you can choose from the existing static collection fo brushes in System.Windows.Media.Brushes (for example control.Background = Brushes.Red or control.Background = Brushes.Transparent)
  • BorderBrush – the brush used to color the border; the border is visible only if the BorderThickness is greater than zero. See Background for types of brushes.
  • BorderThickness – the size of the border; can be individually specified for the left, top, right and bottom locations.
  • ClipToBounds – set to true if you want to clip the control’s content so that it fits in the size of the containing element.
  • FontFamily – the font name used to render the text.
  • FontSize – the font size used to render the text.
  • FontStretch – used to specify the stretch of the font on screen: Condensed, Expanded, ExtraCondensed, ExtraExpanded, Medium, Normal, SemiCondensed, SemiExpanded, UltraCondensed, UltraExpanded. Usage: control.FontStretch = FontStretches.Condensed
  • FontStyle – used to specify the style of the font: Normal, Italic, Oblique. Usage: control.FontStyle=FontStyles.Italic
  • FontWeight – used to specify the wight of the font: Black, Bold, DemiBold, ExtraBlack, ExtraBold, ExtraLight, Heavy, Light, Medium, Normal, Regular, SemiBold, Thin, UltraBlack, UltraBold, UltraLight. Usage: control.FontWeight=FontWeights.Bold
  • Foreground – the brush used to color the border; See Background for types of brushes.
  • Height – the requested height of the control; if you set to Auto in XAML, then the value is double.Nan in code-behind.
  • HorizontalAlignment – sets the horizontal alignment of the control inside the containing parent element.
  • HorizontalContentAlignment – sets the horizontal alignment of the control’s content
  • Margin – specifies the margin of the control on the left, top, right and bottom
  • Name – the unique identifier for the RibbonTab; keep in mind that this field must not contain spaces or special characters – otherwise you will probably get such an exception at runtime: System.Windows.Markup.XamlParseException: “Cannot create instance of ‘Window1’ defined in assembly ‘WPFRibbonExample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’. Exception has been thrown by the target of an invocation.  Error in markup file ‘Window1.xaml’ Line 1 Position …”
  • MinHeight, MinHeight – the minimum sizes of the control
  • MaxWidth, MaxWidth – the maximum sizes of the control
  • Padding – specifies the padding of the control on the left, top, right and bottom
  • Template – specifies the control’s template
  • VerticalAlignment – sets the vertical alignment of the control inside the containing parent element.
  • VerticalContentAlignment – sets the vertical alignment of the control’s content
  • Width – the requested width of the control; if you set to Auto in XAML, then the value is double.Nan in code-behind.

Step 1: Adding Tabs

From XAML

In the main window, inside the ribbon tab you can define as many RibbonTabs as you like, like this, for example:

<Grid>
   <ribbon:Ribbon Name="ribbon">
      <ribbon:RibbonTab Name="RibbonTab1" Label="Ribbon Tab 1">
      </ribbon:RibbonTab>
      <ribbon:RibbonTab Name="RibbonTab2" IsSelected="True" Label="Ribbon Tab 2">
      </ribbon:RibbonTab>
   </ribbon:Ribbon>
</Grid>

So, the displayed name of the ribbon is the specified by the Label property.

From Code-Behind

private void AddRibbon1OnTab()
{
   // create a tab
   RibbonTab tab1 = new RibbonTab();
   tab1.Label = "Tab 1 added from code";

   // add it to the ribbon, after the existing tabs
   ribbon.Tabs.Add(tab1);
}
private void AddRibbon2OnTab()
{
    // create the tab
   RibbonTab tab2 = new RibbonTab();
   tab2.Label = "Tab 2 added from code";
   // give extra space for the tab's label
   tab2.Width = 200;

   // add the tab on the ribbon, at a specified position (for example, the first tab)
   int specifiedPosition = 0;
   ribbon.Tabs.Insert(specifiedPosition, tab2);
 }

The application will look like this:

RibbonTab’s Properties

For each RibbonTab, there are some specific properties that might come in useful:

  • Label – the visual title of the RibbonTab
  • IsOpen – gets a value indicating that the tab is opened
  • IsSelected – gets or sets a value indicating that the current tab will be selected when the application starts; by default, if you don’t specify which tab should be selected, the first tab will be selected.
  • GroupSizeReductionOrder – specifies the order for the inner groups to resize when the tab content does not have enough space to show all the groups. I will give you an example for this property later on, in the next tutorials

Why some properties seem to have no visual effect?

You might think that some properties do not have any visual impact on the ribbon layout. For example, if you change the VerticalAlignment, the label will look the same. But if you change the Height of the tab to 80 and set the VerticalAlignment to Bottom, you might just make the label dissapear under the ribbon.

So, the explanation is rather simple: each control has a more complex layout or template than the one we see and changing the properties of the parent (in this case the tab) might trigger some changes (or no changes) in the inner controls (for example, the label). But more about the ribbon controls’ templates on the next tutorial, when we will also try to identify the inner controls and change the layout of some ribbon controls.

Issues

1) If you specify a larger width for the tab than the one the label actually needs, the label will be aligned left, and even if you set the HorizontalAlignment and HorizontalContentAlignment to centered, it will not change. So my suggestion would be not to change the default width of the tab, which is computed just right for the label text to fit in.

2) Unfortunately, it seems that if you set a tab as selected from code behind and you also have at least a tab defined as selected in the XAML, you will end up with 2 selected tabs, but the actual content displayed will be the one on the XAML (this probably is a bug, but hope it will be solved in V1). For example, if we would have in the code behind part:

private void AddRibbon3OnTab()
{
   // create a tab
   RibbonTab tab3 = new RibbonTab();
   tab3.Label = "Tab 3 added from code";
   tab3.IsSelected = true;

   // add it to the ribbon, after the existing tabs
   ribbon.Tabs.Add(tab3);
}

Knowing that “Ribbon Tab 2” is selected in the XAML part, when the application starts it will look like this:

Step 2: Adding Groups

First off, I have to emphasise that you should not add an empty group on a ribbon tab. Not only that it will not be rendered, but you will also get an exception when that tab is selected: System.NullReferenceException:Object reference not set to an instance of an object. So for this example, I will add a simple RibbonLabel inside every group, just to proove the concept and afterwards we will move on to adding other controls as well.

I will also remove all the tabs added in the previous step, except for tab1 declared in XAML, which I will use to add groups on.

From XAML

First of all we will have to declare a RibbonCommand inside the ResourceDictionary tag, like this:

<ribbon:RibbonCommand x:Key="GroupDialogLauncherCommand" x:Name="GroupDialogLauncherCommand"
      Executed="xamlGroupDialogLauncher_Executed"
      LabelTitle="Group from XAML"
      />

As you can see, the images are not relevant, but the LabelTitle and Executed handler are. The LabelTitle will define the displayed name of the group and the specified Executed handler will be triggered if the RibbonGroup has the DialogLauncher enabled. So, the next step is to add the group and link the command to it.

<ribbon:RibbonTab Name="RibbonTab1" Label="Ribbon Tab 1">
   <ribbon:RibbonGroup HasDialogLauncher="True" Command="{StaticResource GroupDialogLauncherCommand}">
     <ribbon:RibbonLabel Content="Test Label"></ribbon:RibbonLabel>
   </ribbon:RibbonGroup>
</ribbon:RibbonTab>

Here you can observe that the RibbonGroup has a DialogLauncher, which means it will have a small icon on the bottom-right of the group, which clicked will execute the xamlGroupDialogLauncher_Executed method, as specified in the associated ribbon command. Inside the group we have a simple RibbonLabel

void xamlGroupDialogLauncher_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Open the Dialog Launcher for the Group added in XAML");
}

From Code-Behind

You can get the exact group, writing C# code:

private void AddGroupOnTab()
{
// create the group
RibbonGroup group = new RibbonGroup();

// create command in order to set the group's label
RibbonCommand cmd = new RibbonCommand();
cmd.LabelTitle = "Group from Code Behind";
cmd.Executed += new ExecutedRoutedEventHandler(codeBehindGroupDialogLauncher_Executed);
group.Command = cmd;

// you need to specify the ribbon command in order to set this property
group.HasDialogLauncher = true;

// create the label
RibbonLabel label = new RibbonLabel();
label.Content = "Test Label";

// add the label inside the group
group.Controls.Add(label);

// add the group inside the RibbonTab1
RibbonTab1.Groups.Add(group);
}

void codeBehindGroupDialogLauncher_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Open the Dialog Launcher for the Group added in code-behind");
}

The application now looks like this:

RibbonGroup’s Properties

  • Command – the associated RibbonCommand, in which you should specify the LabelTitle (the group’s displayed title) and the Executed event handler (that will be triggered if the group has the HasDialogLauncher set to true and the user clicks on the dialog launcher icon). You can also specify the tool tips, but the large and small images are not displayed for this control.
  • HasDialogLauncher – adds an icon in the bottom-right corner of the group, which clicked can open a dialog launcher (much like the Clipboard, Font or Styles groups in Word)
  • IsCollapsed – gets a value indicating the the RibbonGroups is collapsed; it is read-only
  • GroupSizeDefinitions – specifies the way the inner controls are displayed (large or small size, with or without label); I will show you an example in the “Setting the GroupSizeDefinitions” section.
  • Width – you can specify the width of the group so that all the inner controls fit as you want.

Issues

1) If you add an empty RibbonGroup, you will get an exception when that containing RibbonTab is selected: System.NullReferenceException:Object reference not set to an instance of an object.

2) If you set the HasDialogLauncher property to true and don’t specify any RibbonCommand for the RibbonGroup, you will get an System.NullReferenceException:Object reference not set to an instance of an object. This might have some sence because you didn’t specify the event handler to be triggered when the DialogLauncher icon is pressed, but defing the two elements separately makes this error a little strange.

Source Code

You can download the source code for parts 2,3 and 4 of the tutorial from here.

Posted in WPF Ribbon and tagged as , , , , ,

2 comments on “WPF Ribbon (CTP) – Part 2 – Adding tabs and groups

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.