Posted on 26. February 2012

Ribbon Scaling De-mystified

If you want to add a custom group or tab to a CRM2011 ribbon, you're going to need to understand the scaling mechanism. Following the SDK tutorials and other sources around the internet will give you a basic template, but it only starts to become clear when you see it in action. The Ribbon Workbench for CRM2011 allows you to define your own scaling and quickly see how your controls will behave when the window is re-sized without waiting for it to be uploaded and published first. For this reason it makes the Ribbon Workbench a great tool to use to get a better understanding of how it all works.

Ribbon Scaling is basically a way of ensuring that the user experience is as the best it can be when working with windows of different widths. In the old-days of toolbars, if you could fit all the tools into your window widths you had a simple overflow drop down where the rest would appear. This wasn't very helpful when the most commonly used tools were always on the right hand side, because you always had to use the drop down overflow. To overcome this, the ribbon allows full control over how each group changes with the available space meaning that you can make less commonly used buttons shrink, hide the label before the more important ones.

This article is an attempt to de-mystify the rather confusing description of thise mechanism in the SDK (http://msdn.microsoft.com/en-us/library/gg309453.aspx) by using the Ribbon Workbench to show:

  • Adding a custom tab to the application ribbon (Dashboard page)
  • Adding 3 custom groups
  • Defining scaling so that the groups shrink when the window is resized.
  • Changing the template for a group

Before you continue, go ahead and install the Ribbon Workbench if you haven't already.

1. Adding a custom tab to Dashboard page

The Ribbon Workbench uses solutions to define the ribbon customisations, so since we are adding a tab to the dashboard area, we need to create a solution and add the Application Ribbon from 'Client Extensions' as shown here:

Now we open the ribbon workbench and select our solution. To add the custom tab, drag a new tab from the toolbox onto the application ribbon.

Every tab requires a 'TabDisplayRule' to define when and where the Tab is visible. The default TabDisplayRule created by the Ribbon Workbench is defined just to show that tab on the HomePageGrid. In order to make our custom tab only visible in the dashboards area, we first delete the pre-created EntityRule, and then add a PageRule with the Address: /dashboards/dashboard.aspx. This tells the Ribbon that the tab should only be shown when the Url of the current page matches the address provided, which in our case is the dashboards area.

So to re-cap: Delete the pre-created EntityRule:

Add a new Rule to the Tab Display Rule:

Finally, select 'Add Rule' and select 'PageRule'. Select the new Page Rule, and enter the Address: /dashboards/dashboard.aspx

2. Adding three groups to the New Tab

To really see how the Ribbon scaling behaviour works we need to make our ribbon tab big enough so that it does not fit to a window width by adding some more groups and buttons. Drag another 2 group to the tab, and then add 2 buttons to each layout section o1 and isv. I added some 16x16 and 32x32 images by including them in the solution.

At this point I should explain what the layout sections are. Each tab is divided into groups as you know but then each group is sub-divided into layout sections. These are not visible directly to the user when viewed in Dynamics CRM, but are used to control how the tab groups scale when the window is resized. Each group is assigned a Template and this Template in turn defines layout sections and their behaviour when scaling. 

The default template used is 'MSCRM.Template.3'. It defines two Layout Sections with the names 'o1' and 'isv'. You can see the Layout Section names in the Ribbon Workbench to the bottom-left of the dotted divider. 

Using the Ribbon Workbench you don't really need to worry about the xml, but it sometimes help seing what the template definition xml looks like:

<GroupTemplate Id="Mscrm.Templates.3">
          <Layout Title="Large">
            <OverflowSection Type="OneRow" TemplateAlias="o1" DisplayMode="Large" />
            <OverflowSection Type="OneRow" TemplateAlias="isv" DisplayMode="Large" />
          </Layout>
          <Layout Title="Medium">
            <OverflowSection Type="ThreeRow" TemplateAlias="o1" DisplayMode="Medium" />
            <OverflowSection Type="ThreeRow" TemplateAlias="isv" DisplayMode="Medium" />
          </Layout>
          <Layout Title="Small">
            <OverflowSection Type="ThreeRow" TemplateAlias="o1" DisplayMode="Small" />
            <OverflowSection Type="ThreeRow" TemplateAlias="isv" DisplayMode="Small" />
          </Layout>
          <Layout Title="Popup" LayoutTitle="Large" />
</GroupTemplate>

You can see each Layout Section name is called it's TemplateAlias. This is where ribbon controls are positioned in each Layout Section, but setting the Buttons TemplateAlias location.

You will notice that the same TemplateAlias appears more than once in the Template. This is because the Template also defines how the Layout Sections will change size when the Ribbon is scaled using the 'DisplayMode' property. It does this by defining different layouts that each have a 'Title'. In each Layout, the Layout Sections are listed and the Type and DisplayMode are changed. So inside the Mscrm.Template.3 you can see that the 'Large' layout has both 'o1' and 'isv' in the 'Large' mode and as 'OneRow' - this results in 32x32 buttons being shown. There is a 'Small' Layout that has 'o1' and 'isv' in 'Small' DisplayMode with a Type of 'ThreeRow' – this makes them appear as 16x16 buttons with no label text. The only difference between this and the 'Medium' Layout is that the DisplayMode is 'Medium' which shows the Label Text alongside the 16x16 button.

The last Layout is the 'Popup' layout where all group buttons are rendered as a single popup button. Are you with me so far? If not, just take another read of the above, and examine the GroupTemplate Xml to see how it's structured. 

3. Managing Scaling

The important thing to understand at this stage is that at any one time each group can only assigned a single Layout from the chosen template. The Layout is selected via the Tab Scaling settings. In the ribbon workbench, the Tab Scales are shown as the items below the main ribbon button area and define the order in which the Layouts are selected as the window width is shrunk or expanded. The starting Layout is selected by taking the left most Tab Scale for each group. In fact these are special 'Max Scales' that define the Layout to use first and are shaded blue in the Ribbon Workbench. As the window width is shrunk down, every time the ribbon width is too big to fit, the next Tab Scale is picked, and the corresponding Layout is used to make the ribbon shrink in width. Each Tab Scale item shows the name of the group it applied to on top, and the Layout that is selected underneath.

When you first drag a Tab onto the ribbon, the Ribbon Workbench creates only a Max and a Popup scale. This means that when you shrink the ribbon, it will simply start picking the 'Popup' Layout for each group in the order they are specified.

To see this in action, select the 'Group 1 Popup' and you will see that Group 1 converts to a popup group. If then you select the 'Group2 Popup', in turn 'Group 2' 'shrinks' to a popup. By selecting the Tab Scale from left to right is simulating the user shrinking the window width.

I added some images and published the solution to see this happening 'for real'. Here is the window using the Max Scale items:

And now the window is shrunk so that the first Popup layout is selected.

This is quite an extream way of scaling a ribbon, so normally we would want to change this by defining some intermediary scale steps so that we make button smaller and hide their labels to make them smaller. To do this, drag a 'Tab Scale' item from the toolbox onto the Scale portion of the ribbon between 'Group 1 Large' and 'Group 1 Popup'. Select the new item, and then in the properties, change the Size to 'Medium'. This should give you the following:

When the user now shrinks the ribbon, it will first change Group 1 to its 'Medium' layout, and then finally to its 'Popup' layout. By adding more Tab Scales and changing their order, you have complete control over the sequence in which groups change their size.

If you now drag another Tab Scale after the 'Group 1 Medium', select it and change the Group property dropdown to 'Group 2' and the Size property dropdown to 'Small' you will have:

If you publish this the ribbon will scale as the window is shrunk by:
First changing Group 1 to Medium
    then Group 2 to Small
        then Group 1 to Popup
            then Group 2 to Popup
                and finally Group 3 to Popup.
The great thing about the Ribbon Workbench is you can try this out by simply clicking on the Tab Scale Items from left to right to simulate the window being shrunk.

4. Change the template

The default Template.3 is not always going to suit. There are other templates to choose from that CRM 2011 uses in the Standard Ribbons. You can see what these templates are like and use them by clicking on a Group and changing the 'Template' property dropdown list. If you click on Group 3 and select the Template Mscrm.Templates.Flexible.4, you will see the following message.

This message is warning you that the current Tab Scale items for the selected group have a Layout(s) selected that are not contained in the newly chosen Template. If you select Ok, then each Layout that is not found will be re-assigned to the first layout in the selected template. You will now see:

You can see here that the new template selected contains many more Layout sections than before, and there are more Layout Sizes to choose from. If you select a Tab Scale Item for the group, and use the Size drop down you can see all of the available Layouts.

Have a play with this by selecting the different Layout Sizes and see the effect on the buttons. 

The resulting RibbonXml is as follows:

<RibbonDiffXml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <CustomActions>
    <CustomAction Id="demo.Homepage.applicationribbon.tab26.CustomAction" Location="Mscrm.Tabs._children" Sequence="255">
      <CommandUIDefinition>
        <Tab Command="demo.Homepage.applicationribbon.tab26.DisplayRule" Id="demo.Homepage.applicationribbon.tab26" Sequence="255" Title="$LocLabels:demo.Homepage.applicationribbon.tab26.Title">
          <Scaling Id="demo.Homepage.applicationribbon.tab26.Scaling">
            <MaxSize GroupId="demo.Homepage.applicationribbon.tab26.Group0" Id="demo.Homepage.applicationribbon.tab26.MaxSize.0" Sequence="10" Size="Large" />
            <MaxSize GroupId="demo.Homepage.applicationribbon.tab26.Group1" Id="demo.Homepage.applicationribbon.tab26.MaxSize.2" Sequence="15" Size="Large" />
            <MaxSize GroupId="demo.Homepage.applicationribbon.tab26.Group2" Id="demo.Homepage.applicationribbon.tab26.MaxSize.4" Sequence="17" Size="Large" />
            <Scale GroupId="demo.Homepage.applicationribbon.tab26.Group0" Id="demo.Homepage.applicationribbon.tab26.Scale.6" Sequence="18" Size="Medium" />
            <Scale GroupId="demo.Homepage.applicationribbon.tab26.Group1" Id="demo.Homepage.applicationribbon.tab26.Scale.7" Sequence="19" Size="Small" />
            <Scale GroupId="demo.Homepage.applicationribbon.tab26.Group0" Id="demo.Homepage.applicationribbon.tab26.Scale.1" Sequence="20" Size="Popup" />
            <Scale GroupId="demo.Homepage.applicationribbon.tab26.Group1" Id="demo.Homepage.applicationribbon.tab26.Scale.3" Sequence="30" Size="Popup" />
            <Scale GroupId="demo.Homepage.applicationribbon.tab26.Group2" Id="demo.Homepage.applicationribbon.tab26.Scale.5" Sequence="40" Size="Popup" />
          </Scaling>
          <Groups Id="demo.Homepage.applicationribbon.tab26.Groups">
            <Group Id="demo.Homepage.applicationribbon.tab26.Group0" Sequence="10" Template="Mscrm.Templates.3" Title="$LocLabels:demo.Homepage.applicationribbon.tab26.Group0.Title">
              <Controls Id="demo.Homepage.applicationribbon.tab26.Group0.Controls">
                <Button Id="demo.ApplicationRibbon.Button1.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button1.Button.LabelText" Sequence="10" TemplateAlias="o1" />
                <Button Id="demo.ApplicationRibbon.Button2.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button2.Button.LabelText" Sequence="10" TemplateAlias="isv" />
                <Button Id="demo.ApplicationRibbon.Button8.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button8.Button.LabelText" Sequence="20" TemplateAlias="o1" />
                <Button Id="demo.ApplicationRibbon.Button12.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button12.Button.LabelText" Sequence="20" TemplateAlias="isv" />
              </Controls>
            </Group>
            <Group Id="demo.Homepage.applicationribbon.tab26.Group1" Sequence="20" Template="Mscrm.Templates.3" Title="$LocLabels:demo.Homepage.applicationribbon.tab26.Group1.Title">
              <Controls Id="demo.Homepage.applicationribbon.tab26.Group1.Controls">
                <Button Id="demo.ApplicationRibbon.Button3.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button3.Button.LabelText" Sequence="10" TemplateAlias="o1" />
                <Button Id="demo.ApplicationRibbon.Button4.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button4.Button.LabelText" Sequence="10" TemplateAlias="isv" />
                <Button Id="demo.ApplicationRibbon.Button7.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button7.Button.LabelText" Sequence="20" TemplateAlias="o1" />
                <Button Id="demo.ApplicationRibbon.Button11.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button11.Button.LabelText" Sequence="20" TemplateAlias="isv" />
              </Controls>
            </Group>
            <Group Id="demo.Homepage.applicationribbon.tab26.Group2" Sequence="30" Template="Mscrm.Templates.3" Title="$LocLabels:demo.Homepage.applicationribbon.tab26.Group2.Title">
              <Controls Id="demo.Homepage.applicationribbon.tab26.Group2.Controls">
                <Button Id="demo.ApplicationRibbon.Button5.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button5.Button.LabelText" Sequence="10" TemplateAlias="o1" />
                <Button Id="demo.ApplicationRibbon.Button6.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button6.Button.LabelText" Sequence="10" TemplateAlias="isv" />
                <Button Id="demo.ApplicationRibbon.Button9.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button9.Button.LabelText" Sequence="20" TemplateAlias="o1" />
                <Button Id="demo.ApplicationRibbon.Button10.Button" Image32by32="$webresource:new_Image32.png" Image16by16="$webresource:new_Image16.png" LabelText="$LocLabels:demo.ApplicationRibbon.Button10.Button.LabelText" Sequence="20" TemplateAlias="isv" />
              </Controls>
            </Group>
          </Groups>
        </Tab>
      </CommandUIDefinition>
    </CustomAction>
  </CustomActions>
  <Templates>
    <RibbonTemplates Id="Mscrm.Templates" />
  </Templates>
  <CommandDefinitions />
  <RuleDefinitions>
    <TabDisplayRules>
      <TabDisplayRule TabCommand="demo.Homepage.applicationribbon.tab26.DisplayRule">
        <PageRule Address="/dashboards/dashboard.aspx" />
      </TabDisplayRule>
    </TabDisplayRules>
    <DisplayRules />
    <EnableRules />
  </RuleDefinitions>
  <LocLabels>
    <LocLabel Id="demo.ApplicationRibbon.Button1.Button.LabelText">
      <Titles>
        <Title description="1" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button2.Button.LabelText">
      <Titles>
        <Title description="3" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button8.Button.LabelText">
      <Titles>
        <Title description="2" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button12.Button.LabelText">
      <Titles>
        <Title description="4" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.Homepage.applicationribbon.tab26.Group0.Title">
      <Titles>
        <Title description="Group 1" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button3.Button.LabelText">
      <Titles>
        <Title description="5" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button4.Button.LabelText">
      <Titles>
        <Title description="7" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button7.Button.LabelText">
      <Titles>
        <Title description="6" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button11.Button.LabelText">
      <Titles>
        <Title description="8" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.Homepage.applicationribbon.tab26.Group1.Title">
      <Titles>
        <Title description="Group 2" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button5.Button.LabelText">
      <Titles>
        <Title description="9" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button6.Button.LabelText">
      <Titles>
        <Title description="12" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button9.Button.LabelText">
      <Titles>
        <Title description="10" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.ApplicationRibbon.Button10.Button.LabelText">
      <Titles>
        <Title description="13" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.Homepage.applicationribbon.tab26.Group2.Title">
      <Titles>
        <Title description="Group 3" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="demo.Homepage.applicationribbon.tab26.Title">
      <Titles>
        <Title description="New Tab" languagecode="1033" />
      </Titles>
    </LocLabel>
  </LocLabels>
</RibbonDiffXml>

I've attempted here to shown that it's really easy to create custom tabs groups with the Ribbon Workbench, quickly change the Template for each Group and then add Tab Scale Items to control the scaling behaviour. I think the most important point is that development time is greatly reduced because you can play with how the ribbon will scale without waiting for customisations to be uploaded and published first.

The Ribbon Workbench for CRM 2011 is a free download.

If you find an issue with the Ribbon Workbench for Dynamics CRM 2011 or have any suggestions, please send it here.

Happy Ribbon Customising!

Comments are closed