September 2009 - Posts
Before we start to use ribbon features, we must learn the basics of ribbon markup.
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 and their size, order and layout on screen.
So using commands and views is actually just another instance of the MVC design pattern, which allows us to separate business logic from presentation logic.
Now we will write a new WinForms application with ribbon that uses the application menu with simple buttons. We start this sample with the an empty WinForms project that already includes ribbon support (see previous post for details). On the next sections I’ll explain:
- Commands part of the ribbon markup
- Views part of the ribbon markup
- code-behind, responding to ribbon events
As always, the entire code is available at windowsribbon.codeplex.com
General markup review
Just a reminder, our basic ribbon markup looks like this:
<?xml version='1.0' encoding='utf-8'?>
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
<Application.Commands>
</Application.Commands>
<Application.Views>
<Ribbon>
</Ribbon>
</Application.Views>
</Application>
Defining Commands in Ribbon Markup
Following is a definition of some commands in ribbon markup:
<Application.Commands>
<Command Name="cmdButtonNew"
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>
<Command Name="cmdButtonOpen"
Id="1002"
LabelTitle="Open"
LabelDescription="Open Description"
TooltipTitle="Open"
TooltipDescription="Open an existing image.">
<Command.LargeImages>
<Image>Res/Open32.bmp</Image>
</Command.LargeImages>
<Command.SmallImages>
<Image>Res/Open16.bmp</Image>
</Command.SmallImages>
</Command>
<Command Name="cmdButtonSave"
Id="1003"
LabelTitle="Save"
LabelDescription="Save Description"
TooltipTitle="Save"
TooltipDescription="Save the current image.">
<Command.LargeImages>
<Image>Res/Save32.bmp</Image>
</Command.LargeImages>
<Command.SmallImages>
<Image>Res/Save16.bmp</Image>
</Command.SmallImages>
</Command>
<Command Name="cmdButtonExit"
Id="1004"
LabelTitle="Exit"
LabelDescription="Exit Description"
TooltipTitle="Exit"
TooltipDescription="Exit application.">
<Command.LargeImages>
<Image>Res/Exit32.bmp</Image>
</Command.LargeImages>
<Command.SmallImages>
<Image>Res/Exit16.bmp</Image>
</Command.SmallImages>
</Command>
</Application.Commands>
Explanation: here we define 4 different commands. Each command has properties assigned either by xml attributes or child elements. We use the following (full list is available at “Commands and Resources” on MSDN):
- Name – this name is used later in the views section to reference to this command
- Id – this is the ID of the command. We get it in code when a command an event occurs.
- LabelTitle – the label title of the command
- LabelDescription – the label description of the command
- TooltipTitle – the tooltip title of the command
- TooltipDescription – the tooltip description of the command
- LargeImages – large image filename for the command, usually 32x32 pixels
- SmallImages – small image filename for the command, usually 16x16 pixels
Setting shortcuts to menu items
Setting a key shortcut for a menu item is done by adding “&" in LabelTitle before the letter you want as a shortcut (similar to shortcuts in the “old” menu system), see the LabelTitle of “New” command for example.
Some comments about image resources in Ribbon markup
The filename defined in the markup (like in LargeImages and SmallImages element), should be a valid (relative or full) path to a filename, otherwise the 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.
Update (18.11.2009): convert2bmp is a tool that enables you 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 32x32 and 16x16 should be enough. For more information, see "Specifying Ribbon Image Resources" on MSDN.
Defining Views in Ribbon Markup
Following is a definition of the views part of our ribbon markup:
<Application.Views>
<Ribbon>
<Ribbon.ApplicationMenu>
<ApplicationMenu>
<MenuGroup>
<Button CommandName='cmdButtonNew' />
<Button CommandName='cmdButtonOpen' />
<Button CommandName='cmdButtonSave' />
</MenuGroup>
<MenuGroup>
<Button CommandName='cmdButtonExit' />
</MenuGroup>
</ApplicationMenu>
</Ribbon.ApplicationMenu>
</Ribbon>
</Application.Views>
Explanation: here we define an application menu that contains two menu groups and 4 buttons. The button CommandName attribute points to the command that this button should trigger upon click.
Handling Ribbon Events
Here will see how to handle the event of clicking of one of our menu buttons.
The following code should reside in our main form code file (form1.cs in my sample):
public enum RibbonMarkupCommands : uint
{
cmdApplicationMenu = 1000,
cmdButtonNew = 1001,
cmdButtonOpen = 1002,
cmdButtonSave = 1003,
cmdButtonExit = 1004,
}
This is just a helper enum, to make the code more readable. Every command ID gets a readable symbol.
The important section is our new implementation of the IUICommandHandler.Execute function:
public HRESULT Execute(uint commandId, UI_ExecutionVerb verb, ref PropertyKey key, ref PropVariant currentValue, IUISimplePropertySet commandExecutionProperties)
{
if ((commandId == (uint)RibbonMarkupCommands.cmdButtonNew) &&
(verb == UI_ExecutionVerb.Execute))
{
MessageBox.Show("new button pressed");
}
return HRESULT.S_OK;
}
Update (18.11.2009): Handling ribbon events is now as simple as normal .NET events. Implementing IUICommandHandler by the user is no longer required.
private Ribbon _ribbon;
private RibbonButton _buttonNew;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_buttonNew = new RibbonButton(_ribbon, (uint)RibbonMarkupCommands.cmdButtonNew);
_buttonNew.OnExecute += new OnExecuteEventHandler(_buttonNew_OnExecute);
}
void _buttonNew_OnExecute(PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
MessageBox.Show("new button pressed");
}
Naturally we added to the beginning of the file:
using RibbonLib;
using RibbonLib.Controls;
using RibbonLib.Controls.Events;
using RibbonLib.Interop;
So there you have it, a WinForms application with a Ribbon Application Menu.
That’s it for now,
Arik Poznanski.
So let's see how to use the Ribbon class to add ribbon support to an empty WinForms application.
Step 0 – Download Windows Ribbon for WinForms
As I’ve mentioned in previous posts, you can download the code for my ribbon wrapper library along with numerous samples (currently one..) from windowsribbon.codeplex.com
Also, I remind you to download the helper library, Windows API Code Pack.
Update (18.11.2009): The project doesn’t depends anymore on Windows API Code Pack.
In this post I'll review how to create your first, ribbon-enabled WinForms application, the result is the sample application “01-AddingRibbonSupport”, included on the site.
Step 1 – Reference Windows Ribbon for WinForms
Create a new C# WinForms application and add a reference to our developed library, Ribbon.dll
Also, add to your main form (form1.cs) the following lines:
using RibbonLib;
using RibbonLib.Interop;
public partial class Form1 : Form, IRibbonForm
{
private Ribbon _ribbon = new Ribbon();
...
Step 2 – Add ribbon markup XML file
Add an empty file named RibbonMarkup.xml to the project
Set the file text to the following:
<?xml version='1.0' encoding='utf-8'?>
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
<Application.Commands>
</Application.Commands>
<Application.Views>
<Ribbon>
</Ribbon>
</Application.Views>
</Application>
Right click on the editor where RibbonMarkup.xml is opened and click properties, now set the Schemas property to: C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\UICC.xsd
This will [visual] assist you in the future while editing the ribbon markup file (try Ctrl+Space on the xml editor to see the ribbon markup syntax).
Note: this is the moment where some of you will discover they didn’t install Windows 7 SDK, so go ahead and fix it, I'll wait.
Step 3 – Set UI compiler to compile markup during build
Step 3.1 – Set pre-build events
Go to: Project Properties -> Build Events -> Pre-build event command line
Add the following 3 lines:
"%PROGRAMFILES%\Microsoft SDKs\Windows\v7.0\Bin\UICC.exe" "$(ProjectDir)RibbonMarkup.xml" "$(ProjectDir)RibbonMarkup.bml" /res:"$(ProjectDir)RibbonMarkup.rc"
"%PROGRAMFILES%\Microsoft SDKs\Windows\v7.0\Bin\rc.exe" /v "$(ProjectDir)RibbonMarkup.rc"
cmd /c "("$(DevEnvDir)..\..\VC\bin\vcvars32.bat") && ("$(DevEnvDir)..\..\VC\bin\link.exe" /VERBOSE /NOENTRY /DLL /OUT:"$(ProjectDir)$(OutDir)$(TargetName).ribbon.dll" "$(ProjectDir)RibbonMarkup.res")"
Explanation:
The first line compiles the ribbon markup file to a binary compressed format, along with a small RC file that describes it.
The second line creates a native win32 resource file to be attached to the project native resources.
The third line creates a resource dll from the native win32 resource file.
Step 3.2 - Compile
Compile, in order to invoke the pre-build events.
Update (18.11.2009): Step 3.3 is no longer needed since the resource is loaded from the resource dll.
Step 3.3 – Add native resource
Go to: Project Properties -> Application -> Resources -> Resource File
Set Resource file to point to: RibbonMarkup.res
When it says it can’t find the file, close the properties window anyway. It will save and find the file.
If you wish to be on the safe side, just set the Resource file to the full path of the file (which is dependent on your project location).
Step 4 – Implement IRibbonForm
Have your main form implement IRibbonForm interface, which is defined in Ribbon.dll, you can follow the following guidelines:
- The Ribbon framework needs the main form window handle for initialization, hence:
public IntPtr WindowHandle
{
get
{
return this.Handle;
}
}
- The Ribbon framework will partly hide your form, unless you write some code that repositions your controls according to the ribbon current height. A simple way of doing this is adding a SplitContainer control to the main form and setting the following properties: (you should change them using the GUI properties, not by code):
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
this.splitContainer1.IsSplitterFixed = true;
this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
this.splitContainer1.SplitterWidth = 1;
Now, all you need to do is put your form controls inside panel2 of the SplitContainer and update panel1 height when the ribbon height changes (panel1 act as a placeholder for the ribbon). The SplitContainer will automatically reposition your controls accordingly. The actual update is done in the IRibbonForm implementation:
public void RibbonHeightUpdated(int newHeight)
{
this.splitContainer1.SplitterDistance = newHeight;
}
- The major part of the communication between the ribbon framework and your application is done by implementing the two following methods
, which we’ll initially give a default implementation:
Update (18.11.2009): These functions should not be implemented by the user anymore, since the Ribbon class now provides a general implementation, thus simplifying the use of the library.
public HRESULT Execute(uint commandId, ExecutionVerb verb, PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
return HRESULT.S_OK;
}
public HRESULT UpdateProperty(uint commandId, ref PropertyKey key, PropVariantRef currentValue, ref PropVariant newValue)
{
return HRESULT.S_OK;
}
Step 5 – Initialize Ribbon Framework on application load
To initialize and destroy the ribbon framework, handle both form’s Load and FormClosed events, respectively:
private void Form1_Load(object sender, EventArgs e)
{
_ribbon.InitFramework(this);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
_ribbon.DestroyFramework();
}
Enjoy your first Ribbon WinForms application
Note: If you run your application and don’t see the ribbon, try to enlarge the window size. The windows ribbon has a feature that if the window size is too small, it doesn’t show. Unfortunately, Visual Studio default form size is too small.
That’s it for now,
Arik Poznanski.
Today we will start looking at some code, but before we begin you might want to know where to find it.
The most updated version of "Windows Ribbon for WinForms" code will be at http://windowsribbon.codeplex.com/
It will include the latest version of the project code and samples of how to use its different features. Note that it is based on the Windows API Code Pack, so make sure you have it if you plan to compile the code.
Update (18.11.2009): The Windows Ribbon for WinForms project is not dependent on Windows API Code Pack anymore, so downloading it is not a must.
Let's get started.
Creating .NET wrappers
The first thing needed for using Windows Ribbon from .NET is converting the C++ / COM definitions to C# ones.
The files relevant to Ribbon are: UIRibbon.idl, UIRibbonKeydef.h and UIRibbonPropertyHelpers.h. Note that UIRibbon.h is not interesting since it is auto-generated from UIRibbon.idl by the MIDL compiler. All these files are installed with Windows 7 SDK.
I won't discuss the details of the conversion since it's a very mechanical process, just change every C++ type and convert it to its corresponding .NET equivalent. If you are interested in these details, there are endless sources of information on .NET interoperability.
Following the Windows API Code Pack convention the file UIRibbon.idl was converted to 4 different files:
-
RibbonProperties.cs – containing Ribbon properties definition
-
RibbonCOMGuids.cs – containing all Ribbon related GUIDs
-
RibbonCOMInterfaces.cs – containing Ribbon interfaces definitions
-
RibbonCOMClasses.cs – containing Ribbon classes definitions
These files are my conversions of the COM interfaces and types used by Windows Ribbon Framework. These files may change as the project continues since surely I had some conversions error that will be discovered only when I'll try to use a certain feature.
The most updated version will be the one on codeplex.
How does the Windows Ribbon Framework work?
The full details are provided in MSDN, which I recommend reading. Here I'll only give a short overview so we are all on the same page.
To initialize a ribbon in your application you need to do the following:
-
Design your ribbon appearance using XAML-like markup.
-
Compile your XAML-like markup using Microsoft Ribbon Markup Compile, provided with Windows 7 SDK.
-
Have the binary output of the markup compiler stored as a (unmanaged) resource of your application.
-
On application load,
CoCreateInstance the
UIRibbonFramework class which implements
IUIFramework interface
-
-
Call
framework.LoadUI which loads the pre-compiled resource and shows the actual ribbon.
What have I done, up until now?
In order to facilitate the use of the ribbon within .NET applications we will create a singleton class that will be used as a façade for the Windows Ribbon Framework.
Update (10.11.2009): Ribbon class is no longer singleton to support applications with two ribbons on different forms.
This class, named Ribbon, will be in charge of initialization and communication with the Windows Ribbon Framework.
The Ribbon class will provide an implementation of IUIApplication and handle all the COM details. The information that it can't supply on its own will be provided by your implementation of the interface IRibbonForm (which I invented, so don't go look for it).
The idea is to have your application provide only the minimal required details for the ribbon to work.
Currently IRibbonForm is defined like this:
/// <summary>
/// IRibbonForm interface should be implemented by the main form who want the ribbon
/// </summary>
public interface IRibbonForm : IUICommandHandler
{
/// <summary>
/// Getter for the main form window handle
/// </summary>
IntPtr WindowHandle { get; }
/// <summary>
/// Called when the ribbon height is changed,
/// allowing the form to reposition its controls so the ribbon doesn't hide them.
/// </summary>
/// <param name="newHeight">new height</param>
void RibbonHeightUpdated(int newHeight);
}
The WindowHandle property is used to supply the parent window handle for the ribbon framework.
The RibbonHeightUpdated function is used to notify your application that the ribbon height has changed. Since the ribbon height might change dynamically (for instance, if you resize your window to a minimum, the ribbon will disappear), you get this notification so you can re-organize your form controls properly (so the ribbon doesn't hides them).
One last note about IRibbonForm interface is that it inherits IUICommandHandler. IUICommandHandler is the interface required by the Ribbon Framework to handle command events. It provides the way for your application to know that a button (or any other ribbon control) has been pressed and thus your action is needed.
Update (18.11.2009): The updated version of the Ribbon class provides an implementation for IUICommandHandler, so IRibbonForm doesn’t inherit anymore from IUICommandHandler.
The Ribbon class currently exposes 2 methods:
-
InitFramework - receives your implementation of the IRibbonForm interface and the resource name that will be used to load the ribbon configuration.
-
DestroyFramework - cleanup code, free Windows Ribbon Framework resources.
These methods should be called when the main application form is loaded and closed, respectively.
Summary
This post turned out to be quite long, so I think I'll just stop here for now.
I've put the library code on codeplex along with a sample application that uses the code to create a simple WinForms application with Ribbon support.
On my next post I'll provide simple details on how to build your first WinForms Ribbon application using what we've developed so far.
That’s it for now,
Arik Poznanski

So here is the plan:
I'll write a series of posts regarding using the Windows Ribbon with .NET WinForms.
The goal:
Having .Net wrappers for using Windows Ribbon in WinForms applications and a set of examples of how to use each and every ribbon feature.
Development methodology
I'll develop a library that will hold all the relevant classes, interfaces and native functions.
The library will use the Windows API Code Pack, since they already implemented good wrappers for some of the shell interfaces we will use.
Update (18.11.2009): The library is not dependent on Windows API Code Pack anymore, though it is still a recommended download.
Also, I'll try to keep my conventions similar to the ones used in the Code Pack.
Along with the library I will develop a sample WinForms application (or more) that will show how to correctly use the library.
The most updated version of the code will be available on codeplex.
Background
So, before we start to code, let's give some background on the subject.
Definition (from MSDN): “The Windows Ribbon (Ribbon) framework is a rich command presentation system that provides a modern alternative to the layered menus, toolbars, and task panes of traditional Windows applications."
In Office 2007 Microsoft introduced a new way to organize UI in an application. The problem with the old UI was that it wasn’t flexible enough to represent the majority of office features. (People actually kept asking for features that already existed but were hidden deep in the menus...)
[Microsoft Word 2007 Ribbon]
After the Office 2007 Ribbon turned out to be a success, many UI companies provided their own implementation for a ribbon control to be used in your application.
When Microsoft realized they were onto something good they decided to supply the Ribbon feature to the general public.
They have released 3 (!) Ribbons:
- MFC version, available in Visual Studio 2008 SP1, to be used by native MFC developer
- WPF version, available in WPF toolkit for .Net 3.5 SP1, to be used by managed WPF developers
- Windows Ribbon, available in Windows 7 as a COM object [and in a future Vista update], to be used by native win32 developers.
So, what about managed WinForms users?
They should use the third, COM based version. So the purpose of these posts is to give you a working example of using the Windows Ribbon within a WinForms application.
Why use Windows Ribbon? Note that the question I want to answer is not "Why use A ribbon control?" but "Why use THIS ribbon control?"
Why not use other ribbon controls? There are dozens of third party controls; some of them are free.
The main reason why to use the Windows Ribbon Framework: It's developed by Microsoft.
This means:
- Since it’s the original one, it contains ALL the features, as opposed to other free/commercial ribbon controls which always have those "not implemented" sections.
- It has COMPLETE support and integration with windows 7 UI & accessibility features. Just think about touch screen support or high DPI screens compatibility.
That’s it for now, hopefully you gained some motivation for the project.
Arik Poznanski
