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 used.
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. every thing 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:
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:
In this example we define a command that will encapsulate the "New" button functionality.
The Command XML element has several properties, we divide them to 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 32×32 pixels.
The SmallImages attribute is used to define the small image filename for the command, usually 16×16 pixels.
Setting image resources in ribbon markup
The filename defined in the markup (like in the LargeImages and SmallImages XML element), 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 images 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 32×32 and 16×16 should be enough. For more information, see "Specifying Ribbon Image Resources" on MSDN.
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:
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 responds to the click on the "New" button we show a message box to the screen:
Few things we should note here:
The first parameter, nCmdID, 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 see now 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
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:
In this case, since the HelpButton requires no resources, the command declaration is as simple as:
Using SplitButton and DropDownButton
SplitButton and DropDownButton are both ribbon UI controls which can hold several buttons and which shows 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-format but does have an obvious default save format.
The following example shows how to define both DropDownButton and SplitButton in a ribbon application:
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:
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 "Checked Changed" Event
Handling the "Checked Changed" event is done exactly the same way we handled the "Button Clicked" event, that is, by implementing 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 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 show 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:
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.
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 part 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 is 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 steps 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 property id which is 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 show first 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:
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 properties values of ribbon UI controls.
That's it for now,