On previous posts, we have seen an
introduction
to the
Windows Ribbon Framework
and learned how to
develop a ribbon enabled application
.
In this post, we continue our review of the various features in the Windows Ribbon Framework. This time we will focus on the most common feature in the ribbon: Buttons.
I assume the concept of a button needs no introduction; however, there are several kinds of buttons available with the Windows Ribbon Framework and in this post, we will review them.
But first, let's dive into the details of how we use the ribbon in an application. The important parts are to define the ribbon user interface using the ribbon markup and then implement handlers for the UI we use.
The ribbon markup is composed of two main sections,
Commands
and
Views
.
Commands and Views
A command is an action that is identified by a number. It can be opening the Save-as dialog, printing the current document, closing the application, etc., everything you can do in a function call.
A view is a graphical representation of [usually several] commands. It defines the type of controls used to activate the commands, their size, order, and layout on the screen.
So using commands and views is actually just another instance of the well-known MVC design pattern, which allows us to separate business logic from presentation logic.
The basic template for all ribbon markup files looks like this:
='1.0'='utf-8'
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
<Application.Commands>
</Application.Commands>
<Application.Views>
<Ribbon>
</Ribbon>
</Application.Views>
</Application>
Commands Section
In the
Commands
section, we define, well, commands. Every command is defined in its own
Command
XML element.
Following is a common definition for a
command
:
<Command Name="cmdButtonNew"
Symbol="ID_CMD_NEW"
Id="1001"
LabelTitle="New"
LabelDescription="New Description"
TooltipTitle="New"
TooltipDescription="Create a new image.">
<Command.LargeImages>
<Image>Res/New32.bmp</Image>
</Command.LargeImages>
<Command.SmallImages>
<Image>Res/New16.bmp</Image>
</Command.SmallImages>
</Command>
In this example, we define a
command
that will encapsulate the "New" button functionality.
Command Properties
The
Command
XML element has several properties, we divide them into categories:
Properties used for referencing the command
The
Name
attribute is used to reference this
command
in the markup, for example, in order to attach a button with this
command
.
The
Symbol
attribute represents the name of the constant that will reference this command, later, when we will write the
command
handler code.
The
Id
attribute is just a way to control what the constant value will be.
Properties used for defining command related resources
The
LabelTitle
attribute is used to define the label title of the
command
.
The
LabelDescription
attribute is used to define the label description of the
command
.
The
TooltipTitle
attribute is used to define the tooltip title of the command.
The
TooltipDescription
attribute is used to define the tooltip description of the
command
.
The
LargeImages
attribute is used to define the large image filename for the
command
, usually 32x32 pixels.
The
SmallImages
attribute is used to define the small image filename for the
command
, usually 16x16 pixels.
Setting image resources in ribbon markup
The filename defined in the markup (like in the
LargeImages
and
SmallImages
XML elements) should be a valid (relative or full) path to a filename, otherwise the Visual C++ Resource Compiler (
rc.exe
) will output a compilation error: “error RC2135: file not found: <filename>”.
The image file format should be BMP with 32 BPP ARGB pixel format. Many image editing programs, like Microsoft Paint, do not preserve the highest order 8-bit alpha channel when saving, thus creating only 24 bit images; the result is that the image will not appear at all.
You can use the tool
convert2bmp
to convert your images to the required format.
Under both image elements, you can put several image files in different sizes, the ribbon framework will choose the best size according to the current DPI setting. For us, normal users, setting two images for 32x32 and 16x16 should be enough. For more information, see "
Specifying Ribbon Image Resources
" on MSDN.
Views Section
The
Views
section defines the UI controls we want to use, and their layout in the ribbon. Following is a definition for a view which has a tab, a group, and a single button:
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab CommandName="cmdTabMain">
<Group CommandName="cmdGroupFileActions">
<Button CommandName="cmdButtonNew" />
</Group>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
The
views
syntax is somewhat self-explanatory, we use the
Tab
element to define a tab, a
Group
element to define a group, and a
Button
element to define a button.
The
CommandName
attribute is used to bind a UI element to a given command (along with its resources). In this example, our button will be bound to the predefined
cmdButtonNew
command
element. This means our button will have the label title, tooltip, and images of this
command
.
Figure 1: Button with command resources
Handling "Button Clicked" Event
As we've seen in the previous post, handling the button click event is done by implementing the
IUICommandHandler::Execute
function of the
IUICommandHandler
instance provided by
IUIApplication
for the given
command ID
.
Following is an example where in response to the click on the "New" button, we show a message box to the screen:
STDMETHODIMP CCommandHandler::Execute(
UINT nCmdID,
UI_EXECUTIONVERB verb,
const PROPERTYKEY* key,
const PROPVARIANT* ppropvarValue,
IUISimplePropertySet* pCommandExecutionProperties)
switch (nCmdID)
case ID_CMD_NEW:
MessageBox(GetForegroundWindow(),
L"New button was clicked", L"New Clicked", 0);
break;
return S_OK;
A few things we should note here:
The first parameter, 0nCmdID
, is the ID
of the command which is bound to the button. In our case, we define this ID
to be 1001
(using the Id
attribute of the command
).
The second parameter, verb
, usually has the value UI_EXECUTIONVERB_EXECUTE
. Two other values it can have are: UI_EXECUTIONVERB_PREVIEW
and UI_EXECUTIONVERB_CANCELPREVIEW
. These values are used with ribbon galleries.
The other parameters are not used in this context.
Other Button Types
Up until now, we have seen the most common button type, which is available to us by using the <Button>
XML element.
We will now see a few more types of buttons, the main difference between the different types are their GUI representations. In fact, all of these buttons are used in the exact same way:
Declare them in the ribbon markup Implement IUICommandHandler::Execute
Using HelpButton
The HelpButton
is a button with a specific GUI. It always has the same predefined image and is always positioned in the same place in the ribbon. Also, there can be at most one help-button in the ribbon.
Figure 2: Help button
Note that despite its name, it doesn't have to handle any help-related functionality. That being said, it is recommended you provide help information using this button, to maintain a consistent user experience with other Windows applications.
To use a HelpButton
in your application, you need to use the following ribbon markup:
<Application.Views>
<Ribbon>
<Ribbon.HelpButton>
<HelpButton CommandName="cmdHelpButton" />
</Ribbon.HelpButton>
<Ribbon.Tabs>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
In this case, since the HelpButton
requires no resources, the command
declaration is as simple as:
<Command Name="cmdHelpButton" Symbol="ID_CMD_HELP">
</Command>
Using SplitButton and DropDownButton
SplitButton
and DropDownButton
are both ribbon UI controls which can hold several buttons and which show these buttons upon clicking on a small arrow button:
Figure 3: SplitButton that contains three buttons
So what is actually the difference between these two?
Well, the difference between them is that DropDownButton
is in fact not a button. This means that clicking on a DropDownButton
only shows the buttons list, but doesn't run any custom code.
On the other hand, SplitButton
is itself a button, which you can respond to. A click on the arrow part will cause it to show the buttons list.
The common use for a DropDownButton
is when you want to expose a set of items which doesn't have an obvious default option. For example, consider the “Rotate
” feature in Microsoft Paint. You can rotate by 90, 180, and 270 degrees, but none of these options is an obvious default.
The common use for a SplitButton
is when you want to expose a set of items which have an obvious default option. For example, consider the “Save As” button in an application that supports several file-formats but does have an obvious default save format.
The following example shows how to define both DropDownButton
and SplitButton
in a ribbon application:
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab CommandName="cmdTabMain">
<Group CommandName="cmdGroupFileActions" SizeDefinition="ThreeButtons">
<Button CommandName="cmdButtonNew" />
<DropDownButton CommandName='cmdDropDownButton'>
<MenuGroup Class='MajorItems'>
<Button CommandName='cmdButtonMoreA' />
<Button CommandName='cmdButtonMoreB' />
<Button CommandName='cmdButtonMoreC' />
</MenuGroup>
</DropDownButton>
<SplitButton>
<SplitButton.ButtonItem>
<Button CommandName='cmdButtonMoreB' />
</SplitButton.ButtonItem>
<SplitButton.MenuGroups>
<MenuGroup Class='MajorItems'>
<Button CommandName='cmdButtonMoreA' />
<Button CommandName='cmdButtonMoreB' />
<Button CommandName='cmdButtonMoreC' />
</MenuGroup>
</SplitButton.MenuGroups>
</SplitButton>
</Group>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
Note that in the DropDownButton
XML element, you define only the buttons in the buttons list. On the other hand, the SplitButton
XML element contains a definition for both the buttons list and a specific default button (defined in the SplitButton.ButtonItem
element).
The commands bound to these buttons are defined and handled similarly to the commands we already saw.
CheckBox and ToggleButton
CheckBox
and ToggleButton
are two ribbon UI controls that represent a button with a Boolean state. The sole difference between the two is their GUI representation. The toggle button looks like a button that remains pressed until pressed again. The checkbox
control looks like the familiar checkbox
control we all know and love:
Figure 4: Toggle button and check box
Using CheckBox and ToggleButton
Following is an example of ribbon markup that defines both a ToggleButton
and a CheckBox
:
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab CommandName="cmdTabMain">
<Group CommandName="cmdGroupToggleButton" SizeDefinition="OneButton">
<ToggleButton CommandName="cmdToggleButton" />
</Group>
<Group CommandName="cmdGroupCheckBox">
<CheckBox CommandName="cmdCheckBox" />
</Group>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
What's left for us to know is how to handle the "Checked Changed" event and how to get the current value of the CheckBox
/ ToggleButton
.
Handling the "Checked Changed" Event
Handling the "Checked Changed" event is done exactly the same way we handle the "Button Clicked" event, that is, by implementing the IUICommandHandler::Execute
function.
In order to get the current Boolean value of the CheckBox
, we use another function that IUIFramework
provides, namely, IUIFramework::GetUICommandProperty
. This GetUICommandProperty
function receives three parameters. The first is the command ID
we need for the property from; in our sample, it is ID_CMD_TOGGLE_BUTTON
, which is defined in the auto-generated file RibbonIds.h. The second parameter is the ID
of the property we want to get; in this case, it has the value UI_PKEY_BooleanValue
, which is defined in UIRibbon.h (comes with Windows SDK). The last parameter is the return value of the property.
Setting the value of a property is done similarly using IUIFramework::SetUICommandProperty
.
In the following example, we will see the previous concepts by handling the "Checked Changed" event of a toggle button. We get the Boolean value of the toggle button, negate it, and set it as the Enable
property of the checkbox
:
STDMETHODIMP CCommandHandler::Execute(
UINT nCmdID,
UI_EXECUTIONVERB verb,
const PROPERTYKEY* key,
const PROPVARIANT* ppropvarValue,
IUISimplePropertySet* pCommandExecutionProperties)
HRESULT hr;
HWND hwnd = GetForegroundWindow();
switch (nCmdID)
case ID_CMD_TOGGLE_BUTTON:
BOOL boolValue;
PROPVARIANT var, varNew;
hr = g_pFramework->GetUICommandProperty(ID_CMD_TOGGLE_BUTTON,
UI_PKEY_BooleanValue, &var);
if (FAILED(hr))
return hr;
hr = PropVariantToBoolean(var, &boolValue);
if (FAILED(hr))
return hr;
boolValue = !boolValue;
hr = UIInitPropertyFromBoolean(UI_PKEY_Enabled, boolValue, &varNew);
if (FAILED(hr))
return hr;
hr = g_pFramework->SetUICommandProperty(ID_CMD_CHECK_BOX,
UI_PKEY_Enabled, varNew);
if (FAILED(hr))
return hr;
break;
return S_OK;
The UIInitPropertyFromBoolean
is just a helper function, defined in UIRibbonPropertyHelpers.h, which sets a PROPVARIANT
variable with a boolean value and does a compile time check, on the way, to make sure the property is of Boolean type.
Implementing UpdateProperty
On the previous section, we saw that to set the value of properties, we can use the function IUIFramework::SetUICommandProperty
. Actually, this only works for some of the properties. Other properties are set in a different way, by implementing IUICommandHandler::UpdateProperty
, which we shall review now. The details of which properties can be changed using SetUICommandProperty
and which can be changed only using UpdateProperty
are part of the MSDN documentation of each ribbon UI control.
The second way for updating properties is a two step process:
First, call IUIFramework::InvalidateUICommand
, passing the command ID
and the property ID
which should be invalidated. Second, implement IUICommandHandler::UpdateProperty
. This function will get as parameters the command ID
and the property ID
which are needed by the framework and you should return its value.
Note that the function IUICommandHandler::UpdateProperty
might not get called immediately after calling IUIFramework::InvalidateUICommand
. It will be called only when the ribbon framework will actually need the property value.
In the following example, we first see how to call the InvalidateUICommand
function and how to implement UpdateProperty
so that the text of the checkbox
changes according to the state of the toggle button:
STDMETHODIMP CCommandHandler::Execute(
UINT nCmdID,
UI_EXECUTIONVERB verb,
const PROPERTYKEY* key,
const PROPVARIANT* ppropvarValue,
IUISimplePropertySet* pCommandExecutionProperties)
hr = g_pFramework->InvalidateUICommand(ID_CMD_CHECK_BOX,
UI_INVALIDATIONS_PROPERTY,
&UI_PKEY_Label);
return S_OK;
STDMETHODIMP CCommandHandler::UpdateProperty(
UINT nCmdID,
REFPROPERTYKEY key,
const PROPVARIANT* ppropvarCurrentValue,
PROPVARIANT* ppropvarNewValue)
HRESULT hr = E_FAIL;
if (key == UI_PKEY_Label)
if (nCmdID == ID_CMD_CHECK_BOX)
BOOL boolValue;
PROPVARIANT var;
hr = g_pFramework->GetUICommandProperty(ID_CMD_TOGGLE_BUTTON,
UI_PKEY_BooleanValue, &var);
if (FAILED(hr))
return hr;
hr = PropVariantToBoolean(var, &boolValue);
if (FAILED(hr))
return hr;
if (boolValue)
hr = UIInitPropertyFromString(UI_PKEY_Label,
L"Checkbox Disabled",
ppropvarNewValue);
hr = UIInitPropertyFromString(UI_PKEY_Label,
L"Checkbox Enabled",
ppropvarNewValue);
return hr;
You can find the full code of the sample application used in this post here.
Figure 5: Sample application for this post
In this post, we have learned about the commands and views sections in the markup. We've reviewed what different types of buttons are provided by the ribbon framework, and how to use them. Finally, we saw how to get and set property values of ribbon UI controls.
That's it for now,
Arik Poznanski.
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).
Web02
2.8:2024-01-30:1