Windows Ribbon for WinForms, Part 2 – Basic Ribbon Wrapper

13 בספטמבר 2009

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:

  1. Design your ribbon appearance using XAML-like markup.
  2. Compile your XAML-like markup using Microsoft Ribbon Markup Compile, provided with Windows 7 SDK.
  3. Have the binary output of the markup compiler stored as a (unmanaged) resource of your application.
  4. On application load, CoCreateInstance the UIRibbonFramework class which implements IUIFramework interface
  5. Call framework.Initialize and pass it a reference to your implementation of the IUIApplication interface along with the HWND of your application window.
    • The IUIApplication interface supply a callback for the ribbon framework to call when it needs a command handler, for handling commands (represented as buttons, combos and the other usual controls).
  6. 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

kick it on DotNetKicks.com Shout it

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

5 תגובות

  1. Roland29 במרץ 2010 ב 10:52

    Hello Arik,

    really nice work, thanks for sharing this wrapper.
    There is one thing I want to ask you to check it out. If you minimize a form
    and get back to normal state, the form becomes 30px more in height each time
    you do this.

    I´m developing with VB.Net and did not find any workaround yet. You can also
    crosscheck it with your samples.

    It would be nice, if you can fix it in the wrapper.

    Thanks…

    להגיב
  2. arik4 באפריל 2010 ב 1:28

    Unfortunately I was unable to resolve this one.
    There is a sample for using the Ribbon in .NET provided by Microsoft (not using my wrapper library), called "Preview Ribbon", they have the exact same problem, so the problem is not directly in my wrappers.

    I suspect it has something to do with the WinForms implementation but haven't found a way around it.

    להגיב
  3. Roland6 באפריל 2010 ב 9:41

    Hello Arik,
    thanks for your kind answere. Meanwhile I found a simple workaround using a
    Timer with an Interval of 200.

    Private Sub frmMain_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
    If Me.WindowState = FormWindowState.Minimized Then
    Me.MinimizeTimer.Enabled = True
    End If
    End Sub

    Private Sub MinimizeTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MinimizeTimer.Tick
    If Me.WindowState = FormWindowState.Normal Then
    Me.MinimizeTimer.Enabled = False
    Me.Size = New Size(Me.Width, Me.RestoreBounds.Height – 30)
    End If
    End Sub

    It works perfect for me.

    Thank you!

    להגיב
  4. Erich Rieder14 ביוני 2012 ב 18:56

    I tried to implement your wrapper in a test application and every thing was allright. Then I transfered the ribbon.xml to an existing aplication and also connected the ribbon-control to the xml in the same way, but on the run, the control showed no contents. Any ideas what i coult have forgotten.

    להגיב