WindowsRibbon Internals - harborsiem/WindowsRibbon GitHub Wiki
WindowsRibbon Internals
Windows Ribbon for WinForms Library Internal Design Issues Warning: the rest of this post is extremely boring. It discusses internal details of my ribbon library implementation. This doesn’t change anything for the user of the library.
So now that I’m the only one left, I can discuss some internal details of the library. I’ve just made a major refactoring of the ribbon library.
The ribbon library is composed of:
-
Windows Ribbon Framework API wrappers
-
Main Ribbon class
-
Helper classes for different ribbon controls, such as Button, ComboBox, DropDownGallery etc.
In the old version of the RibbonLib, the controls helper classes had lots of duplicated code. For instance, each control that had images attached to it (LargeImage, SmallImage, … properties) needed to handle those images in the same way (manipulating internal variables, notifying the parent ribbon that an image has invalidated etc.). Now, I don’t know about you, but whenever I copy-paste code I always get this strange feeling that something is wrong. So, after several sample projects I couldn’t take it anymore and decided to redesign this section.
What I’ve done was encapsulate common code in classes, so they can be reused in several controls without duplicating code.
So now every ribbon control is composed from several properties’ providers (like ImagePropertiesProvider and TooltipPropertiesProvider) and events providers (like ExecuteEventsProvider and PreviewEventsProvider).
!Note: The following sentence is hard, but there is an example right after, so be strong.
Each provider component has its own interface which the using-control also implements by delegating the execution to the component.
For example, I have an ImagePropertiesProvider class that implements the interface IImagePropertiesProvider, which exposes 4 image properties (LargeImage, SmallImage, …). In my Button helper class, I create a member variable of type ImagePropertiesProvider and make the Button class also implement IImagePropertiesProvider by calling the corresponding methods on the member variable.
This is one of those cases where multiple inheritance was really missing. As a substitute, what I did was used multiple inheritance of interfaces, aggregation and delegation pattern. So, the controls still have some duplicated code (the delegation code) but this code is really simple and has no logic in it.
Also, each ribbon control has an Execute and UpdateProperty methods it needs to implement according to the properties and events it exposes. So, I’ve made a general implementation which resided in the BaseRibbonControl class that search the implementation of a property or event inside one of the registered providers, thus simplifying this code section in every control (now it doesn’t exist, the simplest way I know).
The results of all these changes are:
-
Shorter code with less duplications.
-
Developing of new helper classes is extremely simple.
-
Cool class diagrams.
Properties Providers Class Diagram
Events Providers Class Diagram
Ribbon Controls Class Diagram
Microsoft recently released PreviewRibbon. It is a sample application that helps you design a ribbon enabled application by giving you a preview of how your markup will look. The application is built as a command line tool that accepts a ribbon markup xml file and displays the result. It is written in C# using WinForms and thus can be used as a sample of how to use the ribbon in a .NET application, which is similar to what I’ve been trying to do.
This is the place to mention RibbonExplorer by Alon Fliess, which is another great tool for previewing a ribbon and manipulating its properties, written in C++/ATL.
Since both Windows Ribbon for WinForms and PreviewRibbon projects use the ribbon thru COM Interop and written in C#, they solve similar problems. So, I’ve decided to review the PreviewRibbon code to learn how they solved some of the issues I’ve faced.
The end result of the review is as follow:
-
I’ve created my own version of PropertyKey class, which is basically a copy of the one PreviewRibbon use, only I’ve separated the PropertyKey definition from ribbon related code.
-
I’ve created my own version of PropVariant class. Decimal value handling is taken from PreviewRibbon (well done!). Vectors handling is taken from Windows API Code Pack.
-
As a small bonus, since now I have my own versions of PropertyKey and PropVariant, the project doesn’t depend anymore on Windows API Code Pack.
-
Changed the naming convention of the ribbon enums (removed UI_ prefix) and ribbon property keys (removed UI_PKEY_ prefix).
Update 25.02.2020: I cannot find PreviewRibbon or RibbonExplorer anymore on the web.