Click here to Skip to main content
Click here to Skip to main content

Ribbon with C++, Post 6: Ribbon Dynamic Structure Capabilities

By , 22 Jul 2011
Rate this:
Please Sign up or sign in to vote.

This is the 6th and last post about using Windows Ribbon Framework features in C++. You can find the previous parts here: Part 1, Part 2, Part 3, Part 4 & Part 5.

In this post we will dive into the ribbon's dynamic structure capabilities, i.e. we will learn about the different ways to change the structure of the ribbon at runtime.

Specifically we will learn about Application Modes and Contextual Tabs. We will see what are these features, when to use them and how.

Application Modes

What is Application Modes?

Application Modes is a feature of the Windows Ribbon Framework that lets you completely change the ribbon according to the current application state.

This feature is best explained with an example. Consider Microsoft Paint. When you open Microsoft Paint you see it in its default "edit mode":

Now, if you choose from the application menu: Print à Print Preview, the entire ribbon changes to the following "print mode":

Notice that in the different application "modes" you have completely different ribbon tabs.

More generally, applications sometimes have different modes in which they show a different user interface, for example:

  • Simple mode VS Advanced mode
  • Regular editor mode VS Print mode

The Windows Ribbon Framework supports the change of its ribbon user interface according to the current application mode. In order to use the ribbon application modes you need to:

  1. Set the available application modes for each ribbon item. This is done in design time.
  2. Set the current application mode. This is done in run time.

To summarize, Application Modes is a feature that allows the ribbon to change its UI according to the current application context.

Application Modes Remarks

  • You can set up to 32 different application modes, each identified by a number between 0 and 31.
  • Application modes can coexist, meaning you can set both "simple" mode and "advanced" mode as active at the same time. Internally the current application modes are represented by a single 32bit variable (which represents a Boolean array of size 32), thus explaining why you can only have 32 modes.
  • Mode 0 is the default mode. So if you don’t set the ApplicationModes attribute, 0 is the default.
  • At least one mode should be set at all times. You can’t disable all the modes (the framework will just ignore your last set).

How to use Application Modes?

Following is an example of an application with two modes: Simple and Advanced. The application loads in simple mode. When the "Switch to Advanced" button is pressed the application changes to the advanced mode and as a result the ribbon changes and additional buttons are added. Note that some buttons appear in both simple and advanced modes.

The end result looks like this:

Figure 1: Demo application in simple mode

Figure 2: Demo application in advanced mode
Defining Application Modes in Ribbon Markup

Following is how we set the ApplicationModes attribute on various visual elements:

<?xml version='1.0' encoding='utf-8'?>
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
  <Application.Commands>
    ?
  </Application.Commands>

  <Application.Views>
    <Ribbon>
      <Ribbon.Tabs>
        <Tab CommandName="cmdTabMain"
           ApplicationModes="0,1">
          <Group CommandName="cmdGroupCommon"
              SizeDefinition="ThreeButtons"
              ApplicationModes="0,1">
            <Button CommandName="cmdButtonNew" />
            <Button CommandName="cmdButtonOpen" />
            <Button CommandName="cmdButtonSave" />
          </Group>
          <Group CommandName="cmdGroupSimple"
              SizeDefinition="TwoButtons"
              ApplicationModes="0">
            <Button CommandName="cmdButtonSwitchToAdvanced" />
            <Button CommandName="cmdButtonMoreA" />
          </Group>
          <Group CommandName="cmdGroupAdvanced"
              SizeDefinition="FourButtons"
              ApplicationModes="1">
            <Button CommandName="cmdButtonSwitchToSimple" />
            <Button CommandName="cmdButtonMoreA" />
            <Button CommandName="cmdButtonMoreB" />
            <Button CommandName="cmdButtonMoreC" />
          </Group>
        </Tab>
      </Ribbon.Tabs>
    </Ribbon>
  </Application.Views>
</Application>

Note we didn't specify the commands sections since there is nothing new in this respect.

In this example we create a tab with 3 groups in it: Common, Simple and Advanced. The common group should always appears so we set its ApplicationModes attribute to “0,1”. The simple group should only appear in simple mode (0). Similarly, the advanced group should only appear in advanced mode (1). Note that the tab element should appear in both modes, so you must also set its ApplicationModes attribute to “0,1”.

ApplicationModes can be set on the following elements:

  • Core tabs (as opposed to contextual tabs, which we will soon review).
  • Groups which are children of core tabs.
  • Button, SplitButton and DropDownButton but only when those controls are in the application menu.
Changing the Application Mode at runtime

Following is the command handler implementation for the two ribbon buttons, “Switch to Simple” and “Switch to Advanced”; each button changes the current application mode.

STDMETHODIMP CCommandHandler::Execute(
   UINT nCmdID,
   UI_EXECUTIONVERB verb,
   const PROPERTYKEY* key,
   const PROPVARIANT* ppropvarValue,
   IUISimplePropertySet* pCommandExecutionProperties)
   {
      switch (nCmdID)
      {
           ?
      
      case ID_CMD_SWITCH_TO_ADVANCED:
           // set advanced mode
           g_pFramework->SetModes(UI_MAKEAPPMODE(1));
           break;
      
      case ID_CMD_SWITCH_TO_SIMPLE:
           // set simple mode
           g_pFramework->SetModes(UI_MAKEAPPMODE(0));
           break;
      }
      
      return S_OK;
}

The UI_MAKEAPPMODE macro is just a simple helper that converts an index number to a 32bit integer with the index bit set. It is defined in UIRibbon.h like this:

#define UI_MAKEAPPMODE(x) (1 << (x))

Of course, you can set several modes at the same time. Although in our application it doesn't make any sense, you can use the following code to set both 0 and 1 application modes:

g_pFramework->SetModes(UI_MAKEAPPMODE(0) | UI_MAKEAPPMODE(1));

Contextual Tabs

What is Contextual Tabs?

Contextual tabs are additional tabs that appear when you enable their context. For example, in Microsoft Word 2007 / 2010, when you select a table in your document, you get two additional tabs (Design and Layout) that contain commands relevant only to tables. Put another way, the Design and Layout tabs are shown only if the "table context" is available.

Figure 3: Microsoft Word 2010 with two Contextual Tabs: Design and Layout

When working with Contextual Tabs the basic working unit is a TabGroup, which is a group of contextual tabs with the same context. For example, in figure 3, you can see the tab group named "Table Tools".

A TabGroup has a property named ContextAvailable (Property Identifier: UI_PKEY_ContextAvailable) of type UI_CONTEXTAVAILABILITY which can have the following values:

  • UI_CONTEXTAVAILIBILITY_ACTIVE – Meaning the context is currently available and the tab group should be active (i.e. selected).
  • UI_CONTEXTAVAILIBILITY_AVAILABLE – Meaning the context is currently available (but the tabs are not necessarily active).
  • UI_CONTEXTAVAILIBILITY_AVAILABLE – Meaning the context is currently not available (hence the additional tabs are hidden).

How to use Contextual Tabs?

Following is an example of an application that uses contextual tabs. We define two tabs, "Design" and "Layout" which are in the same tab group. In this example the context will be set and unset by pressing the "Select" button and "Unselect" button respectively. Of course, in a real application you should set the context according to a real context change.

The end result looks like this:

Figure 4: Demo application before setting the "Table Tools" context

Figure 5: Demo application after setting the "Table Tools" context
Defining Contextual Tabs in Ribbon Markup

Following is the views section for defining contextual tabs. The commands section is straightforward.

<?xml version='1.0' encoding='utf-8'?>
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
  <Application.Commands>
    ...
  </Application.Commands>

  <Application.Views>
    <Ribbon>
      <Ribbon.ContextualTabs>
        <TabGroup CommandName='cmdTabGroupTableTools'>
          <Tab CommandName='cmdTabDesign'>
            <Group CommandName='cmdGroupDesign'
                SizeDefinition='ThreeButtons'>
              <Button CommandName='cmdButtonDesign1' />
              <Button CommandName='cmdButtonDesign2' />
              <Button CommandName='cmdButtonDesign3' />
            </Group>
          </Tab>
          <Tab CommandName='cmdTabLayout'>
            <Group CommandName='cmdGroupLayout'
                SizeDefinition='TwoButtons'>
              <Button CommandName='cmdButtonLayout1' />
              <Button CommandName='cmdButtonLayout2' />
            </Group>
          </Tab>
        </TabGroup>
      </Ribbon.ContextualTabs>
      <Ribbon.Tabs>
        <Tab CommandName="cmdTabMain">
          <Group CommandName="cmdGroupCommon"
              SizeDefinition="FiveButtons">
            ...
            <Button CommandName='cmdButtonSelect' />
            <Button CommandName='cmdButtonUnselect' />
          </Group>
          ...
        </Tab>
      </Ribbon.Tabs>
    </Ribbon>
  </Application.Views>
</Application>

Note the new Ribbon.ContextualTabs section, where we define a single TabGroup for “Table Tools”, with two contextual tabs, “Design” and “Layout”. Each tab has some buttons in it. In addition we define in the main tab two buttons that we will use to set and unset the “Table Tools” context.

Setting Context for Contextual Tabs at Runtime

Following is the command handler implementation for the two ribbon buttons, “Select” and “Unselect”; each button changes the availability of the "Table Tools" context.

STDMETHODIMP CCommandHandler::Execute(
     UINT nCmdID,
     UI_EXECUTIONVERB verb,
     const PROPERTYKEY* key,
     const PROPVARIANT* ppropvarValue,
     IUISimplePropertySet* pCommandExecutionProperties)
 {
     PROPVARIANT varNew;
 
    switch (nCmdID)
     {
         ?
         case ID_CMD_SELECT:
             // mark context as active
             UIInitPropertyFromUInt32(UI_PKEY_ContextAvailable,
                                         UI_CONTEXTAVAILABILITY_ACTIVE, &varNew);
             g_pFramework->SetUICommandProperty(ID_CMD_TABGROUP_TABLE,
                                         UI_PKEY_ContextAvailable, varNew);
             break;
 
        case ID_CMD_UNSELECT:
             // mark context as not available
             UIInitPropertyFromUInt32(UI_PKEY_ContextAvailable, 
                                        UI_CONTEXTAVAILABILITY_NOTAVAILABLE, &varNew);
             g_pFramework->SetUICommandProperty(ID_CMD_TABGROUP_TABLE,
                                         UI_PKEY_ContextAvailable, varNew);
             break;
     }
 
    return S_OK;
 }

Summary

In this post we have learned about the different ways we can use to change the structure of the ribbon at runtime. We have seen how to use Application Modes to completely change the ribbon user interface according to the current application state. We have also seen how to use Contextual Tabs which enable us to add tabs depending on the current context.

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

That's it for now, Arik Poznanski.

License

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

About the Author

Arik Poznanski
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).
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionExcellent work PinmvpRichard MacCutchan24-Jul-11 3:48 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 22 Jul 2011
Article Copyright 2011 by Arik Poznanski
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid