Click here to Skip to main content
15,885,366 members
Articles / All Topics

Ribbon with C++, Part 4: Layout Controls in Windows Ribbon Framework

Rate me:
Please Sign up or sign in to vote.
4.50/5 (5 votes)
16 Jun 2011Ms-PL10 min read 23K   10   1
This is the 4th post about Windows Ribbon Framework features. On previous posts we have introduced the Windows Ribbon Framework, shown a complete example of how to develop a ribbon enabled application and reviewed the different buttons-based UI controls that the ribbon framework provides.

This is the 4th post about Windows Ribbon Framework features. On previous posts we have introduced the Windows Ribbon Framework, shown a complete example of how to develop a ribbon enabled application and reviewed the different buttons-based UI controls that the ribbon framework provides.

In this post we continue our review of the various features in the Windows Ribbon Framework. This time we will focus on a task that every ribbon application developer should address: How to layout UI controls on the ribbon.

We will see how to define tabs and groups, what the tab scaling policy is, and how to control it. After that we will see how to layout controls in groups using predefined layouts and how to define new custom layouts.

On the second half of this post we will see what the ribbon application menu is, and how to add ribbon controls to it.

Arranging Controls in Tabs and Groups

The ribbon is divided into tabs. A Tab encapsulates commands which belong to the same logical category. For example, the "Insert" tab in Microsoft Word contains all the different objects one might insert into a word document, such as picture, shape, table, etc.

clip_image002

Figure 1: Tabs and groups in Microsoft Word 2010

A Group, also called Chunk in some Ribbon APIs, is like a sub category inside a tab.

Defining Tabs and Groups in Ribbon Markup

Defining tabs and groups is done using the Tab and Group XML elements. In the following code snippet we define a ribbon with two tabs, and three groups:

<Application.Views>
    <Ribbon>
        <Ribbon.Tabs>

            <Tab CommandName="cmdTabMain">
                <Group CommandName="cmdGroupFileActions"
                       SizeDefinition="ThreeButtons">
                    <Button CommandName="cmdButtonNew" />
                    <Button CommandName="cmdButtonOpen" />
                    <Button CommandName="cmdButtonSave" />
                </Group>
                <Group CommandName="cmdGroupExit"
                       SizeDefinition="OneButton">
                    <Button CommandName="cmdButtonExit" />
                </Group>
            </Tab>

            <Tab CommandName="cmdTabMore">
                <Group CommandName="cmdGroupMore"
                       SizeDefinition="ThreeButtons">
                    <Button CommandName="cmdButtonMoreA" />
                    <Button CommandName="cmdButtonMoreB" />
                    <Button CommandName="cmdButtonMoreC" />
                </Group>
            </Tab>

        </Ribbon.Tabs>
    </Ribbon>
</Application.Views>

The SizeDefinition attribute of the Group XML element defines what will be the actual layout of the controls inside the group. We will learn more on this attribute later in this post.

Tab Scaling Policy

In order to understand this part you should know that one of the features of the Windows Ribbon Framework is the ability to re-layout your ribbon controls according to the amount of screen space the ribbon has. It pretty much handles this automatically but it does require you to define hints on how you want your layout to scale when the application form gets smaller and smaller.

To better understand the meaning of scaling policy, let's consider the "View" tab in Microsoft Paint when the window is resized.

Following is an image of Microsoft Paint, where the "View" tab is in its fullest form:

Figure 2: View tab in full form

On the next image, the window size has been reduced, which caused the "Zoom" group to scale to a smaller layout:

Figure 3: Zoom group scaled to a smaller layout

On the next image, the window size has been reduced again, resulting in a scale down of the "Display" group:

clip_image002

Figure 4: Display group scaled to a smaller layout

On the next image, the window size has been reduced yet again, resulting in another scale down of the "Zoom" group, this time into a pop-up layout:

Figure 5: Zoom group scaled to popup layout

On the next image, we see what happens when the window size gets too small. The ribbon will disappear completely:

Figure 6: Ribbon disappear when the window size is too small

So, to summarize the example: each group has a starting size, which from now on will be called "ideal size". As the window size gets smaller the groups start to scale down to smaller sizes, but not necessarily in the "normal" order of the groups.

First, the Zoom group scaled to Small size. Then, the Display group scaled to Small size. Finally, the Zoom group scaled to Popup size.

In general, one can define for each group in the ribbon the ideal size for it, which is the default size if the group has an infinite amount of space. The size can be one of four values: Large, Medium, Small and Popup. The actual layout of the controls in the group with different value sizes is dependent on the layout template, which we shall review later on. The Popup value means that the group has shrunk to a single icon that popups the original group (in ideal size) upon clicking.

After defining the ideal size for the group we can define the order of scaling down, meaning which group should scale down first and to what size. In this way you can have your most important controls in your application visible longer that the less important ones.

Following is an example of how to define the tab scaling policy for a specific tab:

<Application.Views>
    <Ribbon>
        <Ribbon.Tabs>

            <Tab CommandName="cmdTabMain">

                <Tab.ScalingPolicy>
                    <ScalingPolicy>
                        <ScalingPolicy.IdealSizes>
                            <Scale Group="cmdGroupFileActions"
                                   Size="Large" />
                            <Scale Group="cmdGroupExit"
                                   Size="Large" />
                        </ScalingPolicy.IdealSizes>
                        <Scale Group="cmdGroupFileActions"
                               Size="Medium" />
                    </ScalingPolicy>
                </Tab.ScalingPolicy>

                <Group CommandName="cmdGroupFileActions"
                       SizeDefinition="ThreeButtons">
                    <Button CommandName="cmdButtonNew" />
                    <Button CommandName="cmdButtonOpen" />
                    <Button CommandName="cmdButtonSave" />
                </Group>
                <Group CommandName="cmdGroupExit"
                       SizeDefinition="OneButton">
                    <Button CommandName="cmdButtonExit" />
                </Group>
            </Tab>

            <Tab CommandName="cmdTabMore">
                <Group CommandName="cmdGroupMore"
                       SizeDefinition="ThreeButtons">
                    <Button CommandName="cmdButtonMoreA" />
                    <Button CommandName="cmdButtonMoreB" />
                    <Button CommandName="cmdButtonMoreC" />
                </Group>
            </Tab>
        </Ribbon.Tabs>
    </Ribbon>
</Application.Views>

In this example we define that the ideal size for both the "File Actions" group and "Exit" group is Large. This is done using the ScalingPolicy.IdealSizes XML element. Then we define the order of scaling when the window size gets smaller. In our example we only define that the next scaling operation should scale the "File Actions" group down to Medium size.

Setting Group Layout

Now we will see how to actually define the layout of the controls inside a ribbon group.

If you remember from the previous examples, we often set a SizeDefinition attribute on the group element. The SizeDefinition is the ribbon markup attribute which allows us, developers, to control the layout of controls in a group.

The value of the SizeDefinition attribute is a name of a layout template. Every layout template defines:

  • A list of controls participating in the layout template.
  • A definition of how to arrange these controls for a given group size. Remember that every group can scale to the following sizes: Large, Medium, Small and Popup.

There are two types of layout templates: Predefined layout templates and Custom layout templates.

Predefined Layout Templates

Microsoft has provided with the Windows Ribbon Framework a list of predefined common layout template so we can use them in our groups without having to specify the exact layout. Up until now, ALL the previous examples used them.

Reminder:

<Group CommandName="cmdGroupFileActions"
       SizeDefinition="ThreeButtons">
    <Button CommandName="cmdButtonNew" />
    <Button CommandName="cmdButtonOpen" />
    <Button CommandName="cmdButtonSave" />
</Group>

The “ThreeButtons” is a name of a predefined layout template that handles the layout for three buttons. This layout template defines two possible sizes: Large and Medium. Note that Popup is always available since it doesn't have a special layout definition (It's always a single icon).

Figure 7: Medium size and Large size defined in ThreeButtons predefined layout template

Following is the list of all available predefined layout templates:

  • OneButton
  • TwoButtons
  • ThreeButtons
  • ThreeButtons-OneBigAndTwoSmall
  • ThreeButtonsAndOneCheckBox
  • FourButtons
  • FiveButtons
  • FiveOrSixButtons
  • SixButtons
  • SixButtons-TwoColumns
  • SevenButtons
  • EightButtons
  • EightButtons-LastThreeSmall
  • NineButtons
  • TenButtons
  • ElevenButtons
  • OneFontControl
  • OneInRibbonGallery
  • InRibbonGalleryAndBigButton
  • InRibbonGalleryAndButtons-GalleryScalesFirst
  • ButtonGroups
  • ButtonGroupsAndInputs
  • BigButtonsAndSmallButtonsOrInputs

Their exact layout can be found at Customizing a Ribbon Through Size Definitions and Scaling Policies on MSDN.

Defining Custom Layout Templates

Custom layout templates can be defined in two ways: Inline and Standalone.

Standalone definition Standalone means you define the layout once, under the Ribbon.SizeDefinitions markup element and then use its name in your group definition, exactly like the predefined layout templates.

For example, we want to define a layout that is consistent with the Microsoft WordPad "Paragraph" group:

Figure 8: Microsoft WordPad

Defining such a layout template in a standalone definition is done like this:

<Ribbon.SizeDefinitions>
    <SizeDefinition Name="ParagraphLayout">
        <ControlNameMap>
            <ControlNameDefinition Name="button1" />
            <ControlNameDefinition Name="button2" />
            <ControlNameDefinition Name="button3" />
            <ControlNameDefinition Name="button4" />
            <ControlNameDefinition Name="button5" />
            <ControlNameDefinition Name="button6" />
            <ControlNameDefinition Name="button7" />
            <ControlNameDefinition Name="button8" />
            <ControlNameDefinition Name="button9" />
        </ControlNameMap>
        <GroupSizeDefinition Size="Large">
            <Row>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button1"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button2"
                                           IsLabelVisible="false" />
                </ControlGroup>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button3"
                                           IsLabelVisible="false" />
                </ControlGroup>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button4"
                                           IsLabelVisible="false" />
                </ControlGroup>
            </Row>
            <Row>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button5"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button6"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button7"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button8"
                                           IsLabelVisible="false" />
                </ControlGroup>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button9"
                                           IsLabelVisible="false" />
                </ControlGroup>
            </Row>
        </GroupSizeDefinition>
    </SizeDefinition>
</Ribbon.SizeDefinitions>

Although this looks intimidating, this is actually pretty simple. First, the ControlNameMap markup element is a definition of placeholders controls used in the layout. In our example we define 9 controls. The mapping between controls in the actual group and controls in the template layout is done according to the order of the controls, define in the ControlNameMap element.

Then we define the actual layout definition for each group size. This is done in a GroupSizeDefinition markup element, where we set the Size attribute to indicate what group scale size we are defining. Remember that different groups' sizes will have different layouts. In our example we define a layout only for the large size.

Then we use the Row markup elements to specify that our layout comes in two lines (three lines is the maximum).

In every row we use ControlGroup elements to specify grouping of controls. Controls which are in the same group have no spacing between them.

Using the standalone custom layout is very simple:

<Group CommandName="cmdGroupParagraph"
       SizeDefinition="ParagraphLayout">
    <Button CommandName="cmdDecreaseIndent" />
    <Button CommandName="cmdIncreaseIndent" />
    <SplitButton>
        <Button CommandName="cmdStartList" />
    </SplitButton>
    <DropDownButton CommandName="cmdLineSpacing">
        <Button />
    </DropDownButton>
    <Button CommandName="cmdAlignLeft" />
    <Button CommandName="cmdAlignCenter" />
    <Button CommandName="cmdAlignRight" />
    <Button CommandName="cmdJustify" />
    <Button CommandName="cmdParagraph" />
</Group>

Figure 9: ParagraphLayout custom layout template

Inline definition Inline means you write the custom layout definition inside your actual group definition, instead of in a general place where it can serve other groups.

Here is the same example as before, only now we use an inline version of the custom layout template:

<Group CommandName="cmdGroupParagraph">
    <SizeDefinition>
        <ControlNameMap>
            <ControlNameDefinition Name="button1" />
            <ControlNameDefinition Name="button2" />
            <ControlNameDefinition Name="button3" />
            <ControlNameDefinition Name="button4" />
            <ControlNameDefinition Name="button5" />
            <ControlNameDefinition Name="button6" />
            <ControlNameDefinition Name="button7" />
            <ControlNameDefinition Name="button8" />
            <ControlNameDefinition Name="button9" />
        </ControlNameMap>
        <GroupSizeDefinition Size="Large">
            <Row>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button1"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button2"
                                           IsLabelVisible="false" />
                </ControlGroup>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button3"
                                           IsLabelVisible="false" />
                </ControlGroup>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button4"
                                           IsLabelVisible="false" />
                </ControlGroup>
            </Row>
            <Row>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button5"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button6"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button7"
                                           IsLabelVisible="false" />
                    <ControlSizeDefinition ControlName="button8"
                                           IsLabelVisible="false" />
                </ControlGroup>
                <ControlGroup>
                    <ControlSizeDefinition ControlName="button9"
                                           IsLabelVisible="false" />
                </ControlGroup>
            </Row>
        </GroupSizeDefinition>
    </SizeDefinition>
    <Button CommandName="cmdDecreaseIndent" />
    <Button CommandName="cmdIncreaseIndent" />
    <SplitButton>
        <Button CommandName="cmdStartList" />
    </SplitButton>
    <DropDownButton CommandName="cmdLineSpacing">
        <Button />
    </DropDownButton>
    <Button CommandName="cmdAlignLeft" />
    <Button CommandName="cmdAlignCenter" />
    <Button CommandName="cmdAlignRight" />
    <Button CommandName="cmdJustify" />
    <Button CommandName="cmdParagraph" />
</Group>

Arranging Controls in the Application Menu

Every ribbon application has an application menu. It is used as the main menu for the application and can be access via a button located on the left of the tabs.

Figure 10: Application menu button in Microsoft Paint

The application menu button opens up a drop down menu that can contain various button like ribbon controls. Note that not all of the ribbon controls can be used in the application menu.

Defining Application Menu in Ribbon Markup

Defining an application menu in the ribbon markup is extremely simple:

<Application.Views>
    <Ribbon>
        <Ribbon.ApplicationMenu>
            <ApplicationMenu>
                <MenuGroup Class="MajorItems">
                    <Button CommandName='cmdButtonNew' />
                    <Button CommandName='cmdButtonOpen' />
                    <Button CommandName='cmdButtonSave' />
                </MenuGroup>
                <MenuGroup Class="MajorItems">
                    <Button CommandName='cmdButtonExit' />
                </MenuGroup>
            </ApplicationMenu>
        </Ribbon.ApplicationMenu>
    </Ribbon>
</Application.Views>

In this example we define an application menu that contains two menu groups and four buttons.

We use the MenuGroup markup element to group the buttons into logical groups. This creates a separator between the groups, as shown in the following image:

Figure 11: Application menu with menu groups

The MenuGroup markup element has a single attribute, named Class, which can have the value StandardItems or MajorItems. This attribute controls the size of the elements in the menu group.

For example, using the following ribbon markup:

<Application.Views>
    <Ribbon>
        <Ribbon.ApplicationMenu>
            <ApplicationMenu>
                <MenuGroup Class="StandardItems">
                    <Button CommandName='cmdButtonNew' />
                    <Button CommandName='cmdButtonOpen' />
                    <Button CommandName='cmdButtonSave' />
                </MenuGroup>
                <MenuGroup Class="StandardItems">
                    <Button CommandName='cmdButtonExit' />
                </MenuGroup>
            </ApplicationMenu>
        </Ribbon.ApplicationMenu>
    </Ribbon>
</Application.Views>

We get the result:

Figure 12: Application menu with menu group of class StandardItems

Another nice UI tweak we can do using a MenuGroup element is set a title for the group. This is done by attaching a command to the MenuGroup element; the title will be defined according to the LabelTitle attribute of the command.

The end result looks like this:

Figure 13: Application menu with menu group titles

Defining Sub-Menus in Ribbon Markup

Defining sub-menus is done by using two buttons we already know from the previous post, namely, DropDownButton and SplitButton.

Each of them can contain a list of buttons, and as seen before, the difference between the two is that DropDownButton is not a button itself but only a container of such, and SplitButton is both a button and a container of buttons.

Following is an example for creating a sub-menu using a DropDownButton:

<Application.Views>
    <Ribbon>
        <Ribbon.ApplicationMenu>
            <ApplicationMenu>
                <MenuGroup Class="MajorItems"
                           CommandName="cmdMenuGroupFile">
                    <Button CommandName='cmdButtonNew' />
                    <Button CommandName='cmdButtonOpen' />
                    <Button CommandName='cmdButtonSave' />
                </MenuGroup>
                <MenuGroup>
                    <DropDownButton CommandName='cmdDropDownButton'>
                        <MenuGroup Class='MajorItems'>
                            <Button CommandName='cmdButtonMoreA' />
                            <Button CommandName='cmdButtonMoreB' />
                            <Button CommandName='cmdButtonMoreC' />
                        </MenuGroup>
                    </DropDownButton>
                </MenuGroup>
                <MenuGroup Class="MajorItems"
                           CommandName="cmdMenuGroupExit">
                    <Button CommandName='cmdButtonExit' />
                </MenuGroup>
            </ApplicationMenu>
        </Ribbon.ApplicationMenu>
    </Ribbon>
</Application.Views>

The result is shown in the following image:

Figure 14: Application menu with sub-menus

Setting shortcuts to menu items

Setting a key shortcut for a menu item is done by adding “&amp;" in the LabelTitle attribute before the letter you want to use as a shortcut (similar to shortcuts in the “old” menu system). For example see the LabelTitle attribute in the following command definition:

<Command Name="cmdButtonNew"
         Symbol="ID_CMD_NEW"
         LabelTitle="&amp;New"
         LabelDescription="New Description"
         TooltipTitle="New (Ctrl+N)"
         TooltipDescription="Create a new image.">
    <Command.LargeImages>
        <Image>Res/New32.bmp</Image>
    </Command.LargeImages>
</Command>

Pressing the Alt key will now add an underscore under the letter and a small box with the letter in it, as shown in the next image:

Figure 15: Application menu with key modifiers

Note that this way of setting key shortcuts is only valid in the application menu. For setting key shortcuts on ribbon controls in the tabs and groups you should set the Keytip attribute of the attached command.

You can find the full code of the sample application used in this post here.

Figure 16: Sample application for this post

In this post we have learned how to layout UI controls on the ribbon. We've seen how to define groups and tabs, what tab scaling policy is, how to use predefined layouts and how to define custom layouts. Finally, we have seen what the application menu is and how to use it in a ribbon enabled application.

That's it for now, Arik Poznanski.

This article was originally posted at http://feeds.feedburner.com/ArikPoznanskisBlog

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer (Senior) Verint
Israel Israel
Arik Poznanski is a senior software developer at Verint. He completed two B.Sc. degrees in Mathematics & Computer Science, summa cum laude, from the Technion in Israel.

Arik has extensive knowledge and experience in many Microsoft technologies, including .NET with C#, WPF, Silverlight, WinForms, Interop, COM/ATL programming, C++ Win32 programming and reverse engineering (assembly, IL).

Comments and Discussions

 
QuestionBuild error Pin
Martin vanPutten4-Jun-12 3:25
Martin vanPutten4-Jun-12 3:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.