November 2009 - Posts
Windows Ribbon for WinForms library now supports working with recent items in the application menu.
The result of this post is a yet another sample, “16-RecentItems”, found on the project site.
What are recent items?
Recent items are items in a list which appears in the application menu. They doesn’t have to be file names and they doesn’t have to be recent, although it is recommended.
Every item has 3 properties:
- Label – Item name, usually file name without path
- Label Description – Item tooltip, usually full filename path
- Pinned – Boolean that indicates whether the recent item should not be removed from the list
More details can be found at Recent Items on MSDN.
Using RecentItems – Ribbon Markup
Commands section:
<Application.Commands>
...
<Command Name="cmdRecentItems" Id="1005" LabelTitle="Recent Items" />
</Application.Commands>
Views section:
<Application.Views>
<Ribbon>
<Ribbon.ApplicationMenu>
<ApplicationMenu CommandName="cmdApplicationMenu">
<ApplicationMenu.RecentItems>
<RecentItems CommandName="cmdRecentItems" EnablePinning="true" MaxCount="7" />
</ApplicationMenu.RecentItems>
...
</ApplicationMenu>
</Ribbon.ApplicationMenu>
</Ribbon>
</Application.Views>
Things to note:
- The “Recent Items” label can be changed to whatever you need (e.g. “Days of the week”).
- Setting EnablePinning attribute to false will hide the pins from the application menu.
- MaxCount attribute specify how many items to display on the application menu.
Using RecentItems – Code Behind
Initialization:
private Ribbon _ribbon;
private RibbonRecentItems _ribbonRecentItems;
List<RecentItemsPropertySet> _recentItems;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_ribbonRecentItems = new RibbonRecentItems(_ribbon, (uint)RibbonMarkupCommands.cmdRecentItems);
_ribbonRecentItems.OnExecute += new OnExecuteEventHandler(_recentItems_OnExecute);
}
private void Form1_Load(object sender, EventArgs e)
{
_ribbon.InitFramework(this);
InitRecentItems();
}
private void InitRecentItems()
{
// prepare list of recent items
_recentItems = new List<RecentItemsPropertySet>();
_recentItems.Add(new RecentItemsPropertySet()
{
Label = "Recent item 1",
LabelDescription = "Recent item 1 description",
Pinned = true
});
_recentItems.Add(new RecentItemsPropertySet()
{
Label = "Recent item 2",
LabelDescription = "Recent item 2 description",
Pinned = false
});
_ribbonRecentItems.RecentItems = _recentItems;
}
RibbonRecentItems is the helper class for working with the recent items feature. It has a property named RecentItems of type IList<RecentItemsPropertySet>. This property contains the list of the recent items. Note that it is the user responsibility for providing this list and update it when needed (add / remove items, change pinned state).
Responding to a click on an item:
void _recentItems_OnExecute(PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
if (key.PropertyKey == RibbonProperties.RecentItems)
{
// go over recent items
object[] objectArray = (object[])currentValue.PropVariant.Value;
for (int i = 0; i < objectArray.Length; ++i)
{
IUISimplePropertySet propertySet = objectArray[i] as IUISimplePropertySet;
if (propertySet != null)
{
PropVariant propLabel;
propertySet.GetValue(ref RibbonProperties.Label,
out propLabel);
string label = (string)propLabel.Value;
PropVariant propLabelDescription;
propertySet.GetValue(ref RibbonProperties.LabelDescription,
out propLabelDescription);
string labelDescription = (string)propLabelDescription.Value;
PropVariant propPinned;
propertySet.GetValue(ref RibbonProperties.Pinned,
out propPinned);
bool pinned = (bool)propPinned.Value;
// update pinned value
_recentItems[i].Pinned = pinned;
}
}
}
else if (key.PropertyKey == RibbonProperties.SelectedItem)
{
// get selected item index
uint selectedItem = (uint)currentValue.PropVariant.Value;
// get selected item label
PropVariant propLabel;
commandExecutionProperties.GetValue(ref RibbonProperties.Label,
out propLabel);
string label = (string)propLabel.Value;
// get selected item label description
PropVariant propLabelDescription;
commandExecutionProperties.GetValue(ref RibbonProperties.LabelDescription,
out propLabelDescription);
string labelDescription = (string)propLabelDescription.Value;
// get selected item pinned value
PropVariant propPinned;
commandExecutionProperties.GetValue(ref RibbonProperties.Pinned,
out propPinned);
bool pinned = (bool)propPinned.Value;
}
}
I know, some explanations are in order.
The OnExecute event is called on two occasions:
- When the user clicks on one of the items.
- When the user changes the pinned status of several items and then closes the menu (either by selecting one of the items or by clicking outside the menu).
When the user clicks on an item, the currentValue argument contains the index of the selected item and commandExecutionProperties argument contains the properties of the selected item. The above code shows how to extract them.
When the user changes the pinned status of several items, the currentValue argument contains the new status of the items. It is the user responsibility to update the items in its own list. otherwise the user’s change won’t appear the next time he opens the menu.
That’s it for now,
Arik Poznanski.
Windows Ribbon for WinForms library now supports using a Context Popup.
The result of this post is a yet another sample, “15-ContextPopup”, found on the project site.
What is a Context Popup?
A context popup is a combination of a small toolbar (called MiniToolbar) and a context menu, which a ribbon enabled application can provide. This popup usually appears when right-clicking an application surface and it usually provide common operation relevant for the clicked surface.
Basically it’s just another way to get to your ribbon commands. In fact, since the MiniToolbar (the upper part of the context popup) can’t be access using the keyboard, Microsoft strongly recommends that every command should be also available using the standard ribbon interface.
More details can be found at Context Popup on MSDN.
Using ContextPopup – Ribbon Markup
Following is an example of defining a context popup. Only the Views section is presented since the Commands section is obvious. The result of this markup is shown in the image above.
<Application.Views>
<ContextPopup>
<ContextPopup.MiniToolbars>
<MiniToolbar Name="MiniToolbar">
<MenuGroup>
<FontControl CommandName="cmdFontControl"/>
</MenuGroup>
<MenuGroup>
<DropDownColorPicker CommandName="cmdDropDownColorPicker" />
<Button CommandName="cmdButtonNew" />
<Button CommandName="cmdButtonOpen" />
<Button CommandName="cmdButtonSave" />
<ComboBox />
</MenuGroup>
</MiniToolbar>
</ContextPopup.MiniToolbars>
<ContextPopup.ContextMenus>
<ContextMenu Name="ContextMenu">
<MenuGroup>
<Button CommandName="cmdButtonNew" />
<Button CommandName="cmdButtonOpen" />
<Button CommandName="cmdButtonSave" />
</MenuGroup>
<MenuGroup>
<DropDownColorPicker CommandName="cmdDropDownColorPicker" />
</MenuGroup>
</ContextMenu>
</ContextPopup.ContextMenus>
<ContextPopup.ContextMaps>
<ContextMap CommandName="cmdContextMap"
ContextMenu="ContextMenu"
MiniToolbar="MiniToolbar" />
</ContextPopup.ContextMaps>
</ContextPopup>
<Ribbon>
</Ribbon>
</Application.Views>
Things to note:
- In the ContextPopup.MiniToolbars element you can define a list of available mini toolbars (upper parts).
- In the ContextPopup.ContextMenus element you can define a list of available context menus (lower parts).
- The actual definition of the context popup resides in the ContextPopup.ContextMaps element, where you can define a list of context popups. For each context popup you need to specify its upper part and lower part.
Using ContextPopup – Code Behind
In order to show the predefined context popups I present here two ways: the recommended way and the convenient way.
The recommended way
Use the method, Ribbon.ShowContextPopup to show a given context popup in a certain location, usually as a response to right clicking:
private Ribbon _ribbon;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
// recommended way
panel2.MouseClick += new MouseEventHandler(panel2_MouseClick);
}
void panel2_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
System.Drawing.Point p = panel2.PointToScreen(e.Location);
_ribbon.ShowContextPopup((uint)RibbonMarkupCommands.cmdContextMap, p.X, p.Y);
}
}
Note that the ShowContextPopup gets the location in screen coordinates, so a transformation using the Control.PointToScreen method is required.
The convenient way
If you are used to program client applications in .NET you must be familiar with ContextMenuStrip class. Every WinForms control has a ContextMenuStrip property where you can attach an instance of a predefined ContextMenuStrip instance, thus letting the .NET framework handle the opening of the context menu for you. Unfortunately the ContextMenuStrip property works only with ContextMenuStrip instances (An IContextMenuStrip interface would be great..), so you can’t easily replace the .NET implementation of a context menu with our new ribbon based implementation.
Following is a hack you can use to achieve this. I’ve created a RibbonContextMenuStrip class that inherits from ContextMenuStrip and hacked my way into showing the ribbon context menu instead of the .NET context menu. The advantage is that you have an easier interface for working with the ribbon context menu:
private Ribbon _ribbon;
private RibbonContextMenuStrip _ribbonContextMenuStrip;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_ribbonContextMenuStrip = new RibbonContextMenuStrip(_ribbon, (uint)RibbonMarkupCommands.cmdContextMap);
// convenient way
panel1.ContextMenuStrip = _ribbonContextMenuStrip;
}
As you can see from the code, it is shorter and use the standard .NET way for setting context menus on controls.
Let’s see the “magic” in action:
public class RibbonContextMenuStrip : ContextMenuStrip
{
private uint _contextPopupID;
private Ribbon _ribbon;
public RibbonContextMenuStrip(Ribbon ribbon, uint contextPopupID)
: base()
{
_contextPopupID = contextPopupID;
_ribbon = ribbon;
}
protected override void OnOpening(CancelEventArgs e)
{
_ribbon.ShowContextPopup(_contextPopupID,
Cursor.Position.X,
Cursor.Position.Y);
e.Cancel = true;
}
}
Note: The RibbonContextMenuStrip is NOT part of the Windows Ribbon for WinForms library. The code is available as part of the sample “15-ContextPopup”. It works but I don’t like it.
Ribbon Properties
This section has nothing to do with context popup.
The ribbon library now supports 3 general properties for the ribbon UI:
- Minimized - Specifies whether the ribbon is in a collapsed or expanded state.
Property Identifier: UI_PKey_Minimized
- Viewable - Specifies whether the ribbon user interface (UI) is in a visible or hidden state.
Property Identifier: UI_PKey_Viewable
- QuickAccessToolbarDock - Specifies whether the quick access toolbar is docked at the top or at the bottom.
Property Identifier: UI_PKey_QuickAccessToolbarDock
Using these properties is as simple as:
private void Form1_Load(object sender, EventArgs e)
{
_ribbon.InitFramework(this);
_ribbon.Viewable = false;
}
That’s it for now,
Arik Poznanski.
Windows Ribbon for WinForms library now supports Contextual Tabs.
The result of this post is a yet another sample, “14-ContextualTabs”, found on the project site.
What are contextual tabs?
Contextual tabs are additional tabs that appear when you enable their context.
For example, in word, when you select a table in your document, you get two additional tabs (Design and Layout) with commands relevant only to tables.
The basic working unit is a TabGroup, which is a group of contextual tabs with the same context.
A TabGroup has a property named ContextAvailable (Property Identifier: UI_PKEY_ContextAvailable) which can have the following values:
- Active – context is currently available and the tab group should be active (=“selected”)
- Available – context is currently available (tabs are not necessarily active).
- NotAvailable – context is currently not available.
More details on this subject can be found at Displaying Contextual Tabs on MSDN.
Using ContextualTabs – Ribbon Markup
Following is the views section for defining contextual tabs. The commands section is straightforward.
<Application.Views>
<Ribbon>
<Ribbon.ContextualTabs>
<TabGroup CommandName='cmdTabGroupTableTools'>
<Tab CommandName='cmdTabDesign'>
<Group CommandName='cmdGroupDesign' SizeDefinition='ThreeButtons'>
<Button CommandName='cmdButtonDesign1' />
<Button CommandName='cmdButtonDesign2' />
<Button CommandName='cmdButtonDesign3' />
</Group>
</Tab>
<Tab CommandName='cmdTabLayout'>
<Group CommandName='cmdGroupLayout' SizeDefinition='TwoButtons'>
<Button CommandName='cmdButtonLayout1' />
<Button CommandName='cmdButtonLayout2' />
</Group>
</Tab>
</TabGroup>
</Ribbon.ContextualTabs>
<Ribbon.Tabs>
<Tab CommandName='cmdTabMain'>
<Group CommandName='cmdGroupMain' SizeDefinition='TwoButtons'>
<Button CommandName='cmdButtonSelect' />
<Button CommandName='cmdButtonUnselect' />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
Here we define a single TabGroup for “Table Tools”, with two contextual tabs, “Design” and “Layout”.
Each tab has some buttons in it.
In addition we define in the main tab two buttons that we will use to set and unset the “Table Tools” context.
Using ContextualTabs – Code Behind
Following is an example of setting the context for a TabGroup thus making it visible.
private Ribbon _ribbon;
private RibbonTabGroup _tabGroupTableTools;
private RibbonButton _buttonSelect;
private RibbonButton _buttonUnselect;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_tabGroupTableTools = new RibbonTabGroup(_ribbon,
(uint)RibbonMarkupCommands.cmdTabGroupTableTools);
_buttonSelect = new RibbonButton(_ribbon,
(uint)RibbonMarkupCommands.cmdButtonSelect);
_buttonUnselect = new RibbonButton(_ribbon,
(uint)RibbonMarkupCommands.cmdButtonUnselect);
_buttonSelect.OnExecute += new OnExecuteEventHandler(_buttonSelect_OnExecute);
_buttonUnselect.OnExecute += new OnExecuteEventHandler(_buttonUnselect_OnExecute);
}
void _buttonSelect_OnExecute(PropertyKeyRef key, PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
_tabGroupTableTools.ContextAvailable = ContextAvailability.Active;
}
void _buttonUnselect_OnExecute(PropertyKeyRef key, PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
_tabGroupTableTools.ContextAvailable = ContextAvailability.NotAvailable;
}
Here we just register to the ribbon buttons execute events and set the context of the TabGroup accordingly. Of course in a real application you might use a more sophisticated logic for setting the context.
That’s it for now,
Arik Poznanski.
Windows Ribbon for WinForms library now supports Application Modes.
The result of this post is a yet another sample, “13-ApplicationModes”, found on the project site.
What are application modes?
It is best to explain using examples. Applications some times have different “modes” in which they show different GUI, for example:
- Simple mode VS Advanced mode
- Regular editor mode VS Print mode
The ribbon framework support changing its GUI according to the current application mode. In order to use the ribbon application modes you need to:
- Set the available application modes for each ribbon item. This is done in design time.
- Set the current application mode. This is done in run time.
To summarize, application modes is a feature that allows the ribbon to change its GUI according to the current application context.
More details on this subject can be found at Reconfiguring the Ribbon with Application Modes on MSDN.
Using ApplicationModes extra remarks
- You can set up to 32 different application modes, each identified by a number between 0 and 31.
- Modes can coexist, meaning you can set both simple mode and advanced mode as active at the same time. Internally the current application modes are represented by a single 32bit variable (which represents a Boolean array of size 32), thus explaining why you can only have 32 modes.
- Mode 0 is the default mode. So if you don’t set the ApplicationModes attribute, 0 is the default.
- At least one mode should be set at all times. You can’t disable all the modes (the framework will just ignore your last set).
Using ApplicationModes – Ribbon Markup
Following is an example of the views section where you set the ApplicationModes attribute:
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab CommandName="cmdTabMain" ApplicationModes="0,1">
<Group CommandName="cmdGroupCommon"
SizeDefinition="ThreeButtons"
ApplicationModes="0,1">
<Button CommandName="cmdButtonNew" />
<Button CommandName="cmdButtonOpen" />
<Button CommandName="cmdButtonSave" />
</Group>
<Group CommandName="cmdGroupSimple"
SizeDefinition="TwoButtons"
ApplicationModes="0">
<Button CommandName="cmdButtonSwitchToAdvanced" />
<Button CommandName="cmdButtonDropA" />
</Group>
<Group CommandName="cmdGroupAdvanced"
SizeDefinition="FourButtons"
ApplicationModes="1">
<Button CommandName="cmdButtonSwitchToSimple" />
<Button CommandName="cmdButtonDropA" />
<Button CommandName="cmdButtonDropB" />
<Button CommandName="cmdButtonDropC" />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
In this example we create a tab with 3 groups in it: Common, Simple and Advanced.
The common group should always appears so we set its ApplicationModes attribute to “0,1”
The simple group should only appear in simple mode (0). Similarly, the advanced group should only appear in advanced mode (1).
Note that the tab element should appear in both modes, so you must also set its ApplicationModes attribute to “0,1”.
ApplicationModes can be set on the following elements:
- Core tabs (as apposed to contextual tabs).
- Groups which are children of core tabs.
- Button, SplitButton and DropDownButton but only when those controls are in the application menu.
ApplicationModes – code behind
Following are two ribbon buttons, “simple” and “advanced”, each changes the current application mode:
private Ribbon _ribbon;
private RibbonButton _buttonSwitchToAdvanced;
private RibbonButton _buttonSwitchToSimple;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_buttonSwitchToAdvanced = new RibbonButton(_ribbon,
(uint)RibbonMarkupCommands.cmdButtonSwitchToAdvanced);
_buttonSwitchToSimple = new RibbonButton(_ribbon,
(uint)RibbonMarkupCommands.cmdButtonSwitchToSimple);
_buttonSwitchToAdvanced.OnExecute +=
new OnExecuteEventHandler(_buttonSwitchToAdvanced_OnExecute);
_buttonSwitchToSimple.OnExecute +=
new OnExecuteEventHandler(_buttonSwitchToSimple_OnExecute);
}
void _buttonSwitchToAdvanced_OnExecute(PropertyKeyRef key, PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
_ribbon.SetModes(1);
}
void _buttonSwitchToSimple_OnExecute(PropertyKeyRef key, PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
_ribbon.SetModes(0);
}
The Ribbon.SetModes method is just a simple wrapper that converts a byte array to a compact 32bit integer and pass it to the relevant framework function:
public void SetModes(params byte[] modesArray)
{
// check that ribbon is initialized
if (!Initalized)
{
return;
}
// calculate compact modes value
int compactModes = 0;
for (int i = 0; i < modesArray.Length; ++i)
{
if (modesArray[i] >= 32)
{
throw new ArgumentException("Modes should range between 0 to 31.");
}
compactModes |= (1 << modesArray[i]);
}
// set modes
Framework.SetModes(compactModes);
}
That’s it for now,
Arik Poznanski.
Using Windows Ribbon for WinForms just got a lot easier.
Warning: Boring post. Talks about changes in the ribbon library and their reasons.
But first, let me start by asking for your forgiveness.
I’m trying to create a library which will be easy to use and so the last change to the library wasn’t backward compatible. Namely, classes names and interfaces have changed.
Rest assured that every single change I made is making the library a little more easier to use. However, for all those who have started using the library, I say: sorry. [This is what you get for using a project in BETA]
So, what have changed?
Classes names
I’ve added a “Ribbon” prefix to all the ribbon controls helper classes. This is to prevent collision with the standard WinForms controls, like Button, ComboBox, etc.
Yea, I know, this is why we have namespaces. However having a WinForms project with both a button and a ribbon button is not a rare case. When this happens the user can’t add “using RibbonLib.Controls;” so almost every other line is cluttered with “RibbonLib.Controls” prefix, for example:
RibbonLib.Controls.Button ribbonButton = new RibbonLib.Controls.Button(_ribbon, commandId);
Instead of:
RibbonButton ribbonButton = new RibbonButton(_ribbon, commandId);
IUICommandHandler Implementation
I’ve added a general implementation of IUICommandHandler (Execute and UpdateProperty functions) to the Ribbon class, so that these methods should not be implemented anymore by the user. This means the user doesn’t need to write anymore the following code in its Form class:
public HRESULT Execute(uint commandId, ExecutionVerb verb, PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerGroup:
_groupColors.Execute(verb, key, currentValue, commandExecutionProperties);
break;
case (uint)RibbonMarkupCommands.cmdButtonsGroup:
_groupButtons.Execute(verb, key, currentValue, commandExecutionProperties);
break;
case (uint)RibbonMarkupCommands.cmdButtonListColors:
_buttonListColors.Execute(verb, key, currentValue, commandExecutionProperties);
break;
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerThemeColors:
_themeColors.Execute(verb, key, currentValue, commandExecutionProperties);
break;
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerStandardColors:
_standardColors.Execute(verb, key, currentValue, commandExecutionProperties);
break;
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerHighlightColors:
_highlightColors.Execute(verb, key, currentValue, commandExecutionProperties);
break;
}
return HRESULT.S_OK;
}
public HRESULT UpdateProperty(uint commandId, ref PropertyKey key, PropVariantRef currentValue, ref PropVariant newValue)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerGroup:
_groupColors.UpdateProperty(ref key, currentValue, ref newValue);
break;
case (uint)RibbonMarkupCommands.cmdButtonsGroup:
_groupButtons.UpdateProperty(ref key, currentValue, ref newValue);
break;
case (uint)RibbonMarkupCommands.cmdButtonListColors:
_buttonListColors.UpdateProperty(ref key, currentValue, ref newValue);
break;
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerThemeColors:
_themeColors.UpdateProperty(ref key, currentValue, ref newValue);
break;
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerStandardColors:
_standardColors.UpdateProperty(ref key, currentValue, ref newValue);
break;
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerHighlightColors:
_highlightColors.UpdateProperty(ref key, currentValue, ref newValue);
break;
}
return HRESULT.S_OK;
}
The new implementation, which resides in the Ribbon class just delegates the call to the correct ribbon control, according to the command ID:
public virtual HRESULT Execute(uint commandID, ExecutionVerb verb, PropertyKeyRef key,
PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
if (_mapRibbonControls.ContainsKey(commandID))
{
_mapRibbonControls[commandID].Execute(verb, key, currentValue,
commandExecutionProperties);
}
return HRESULT.S_OK;
}
public virtual HRESULT UpdateProperty(uint commandID, ref PropertyKey key,
PropVariantRef currentValue,
ref PropVariant newValue)
{
if (_mapRibbonControls.ContainsKey(commandID))
{
_mapRibbonControls[commandID].UpdateProperty(ref key, currentValue,
ref newValue);
}
return HRESULT.S_OK;
}
The _mapRibbonControls is an internal dictionary that contains all the ribbon controls helper classes the user have created in the main form.
Note: I’ve made these functions virtual so that if some user wants direct access to the notifications from the ribbon framework he can still get them by deriving from the Ribbon class and overriding these methods.
Support for Ribbon External DLL
Now you can have your ribbon resource reside in an external dll instead of inside the application executable, as a native resource. This issue was a problem for developers who needed the native resource for other uses (like setting the application icon).
In fact, I’ve made this the default behavior of the ribbon. So now when you call the simplest form of Ribbon.InitFramework, the ribbon library tries to load the ribbon from your_app_name.ribbon.dll and only if it fails to find this file it will revert back to the previous behavior, that is, try to load ribbon from your executable native resource.
Of course you can provide your own dll name to load, or even load it yourself and pass the dll handle (=what returns from LoadLibrary) to the different overloads of Ribbon.InitFramework. This allows you to implement a custom ribbon loading mechanism which can be useful if you wish to load different ribbons on different scenarios, e.g. add localization support (different locale has different ribbon).
What this means for the user of the ribbon library is that he needs to add one more step to the pre-build event. This step will create the ribbon resource dll from the resource file created by previous steps.
So the pre-build events for projects that uses the ribbon library are now:
"%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")"
I know, this looks like a pile of junk, but actually what’s written is:
- UICC – please convert RibbonMarkup.xml to RibbonMarkup.rc
- rc – please convert RibbonMarkup.rc to RibbonMarkup.res
- link – please convert RibbonMarkup.res to YourAppName.ribbon.dll
I’ve updated all the ribbon library samples to use the ribbon resource dll.
That’s it for now,
Arik Poznanski.
Windows Ribbon for WinForms library now supports FontControl control.
The result of this post is a yet another sample, “12-FontControl”, found on the project site.
FontControl Control
FontControl is another special control provided by the Windows Ribbon Framework.
It allows you to choose font family, size, colors and related effects.
It has three types, each exposing a little more functionality then the other:
- Font Only
- Font With Color
- Rich Font
Check Font Control on MSDN for full details on the differences between the types.
FontControl Properties
Following is the list of properties which are unique for FontControl control. The rest of the properties have been reviewed in previous posts.
- FontProperties – This property is of type IPropertyStore and holds all the font specific properties, like Size, Bold, Underline, etc.
In the FontControl helper class I use this property internally to access the other properties but do not expose it to the user, since it has no use other then being an access point to the other properties.
Property Identifier: UI_PKEY_FontProperties
- ChangedProperties – This property contains all the recently changed properties.
The FontControl doesn’t expose it but provides it as one of the parameters in the Execute / Preview / CancelPreview events. For example, if you click on the “Bold” button, the Execute event will be called and the this property will contain only the Bold property.
Property Identifier: UI_PKEY_FontProperties_ChangedProperties
- Family – The selected font family name.
Property Identifier: UI_PKEY_FontProperties_Family
- Size – The size of the font.
Property Identifier: UI_PKEY_FontProperties_Size
- Bold – Flag that indicates whether bold is selected.
Property Identifier: UI_PKEY_FontProperties_Bold
- Italic – Flag that indicates whether italic is selected.
Property Identifier: UI_PKEY_FontProperties_Italic
- Underline – Flag that indicates whether underline is selected.
Property Identifier: UI_PKEY_FontProperties_Underline
- Strikethrough – Flag that indicates whether strikethrough is selected (sometimes called Strikeout).
Property Identifier: UI_PKEY_FontProperties_Strikethrough
- VerticalPositioning – Flag that indicates which one of the Subscript and Superscript buttons are selected, if any.
Property Identifier: UI_PKEY_FontProperties_VerticalPositioning
- ForegroundColor – Contains the text color if ForegroundColorType is set to RGB. The FontControl helper class expose this property as a .NET Color and handles internally the conversion to and from COLORREF structure.
Property Identifier: UI_PKEY_FontProperties_ForegroundColor
- ForegroundColorType – The text color type. Valid values are RGB and Automatic.
If RGB is selected, the user should get the color from the ForegroundColor property.
If Automatic is selected the user should use SystemColors.WindowText.
The FontControl helper class doesn’t expose the ForegroundColorType property. Instead it implements the color selection algorithm internally (i.e. return correct color according to the type property).
Property Identifier: UI_PKEY_FontProperties_ForegroundColorType
- BackgroundColor – Contains the background color if BackgroundColorType is set to RGB. The FontControl helper class expose this property as a .NET Color and handles internally the conversion to and from COLORREF structure.
Property Identifier: UI_PKEY_FontProperties_BackgroundColor
- BackgroundColorType – The background color type. Valid values are RGB and NoColor.
If RGB is selected, the user should get the color from the BackgroundColor property.
If NoColor is selected the user should use SystemColors.Window.
The FontControl helper class doesn’t expose the ForegroundColorType property. Instead it implements the color selection algorithm internally (i.e. return correct color according to the type property).
Property Identifier: UI_PKEY_FontProperties_BackgroundColorType
- DeltaSize – Indicated whether the “Grow Font” or “Shrink Font” buttons were pressed. This property is only available as part of the ChangedProperties property and is not exposed by the FontControl helper class.
Property Identifier: UI_PKEY_FontProperties_DeltaSize
Using FontControl – Ribbon Markup
Commands and Views sections:
<?xml version='1.0' encoding='utf-8'?>
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
<Application.Commands>
<Command Name="cmdTabMain" Id="1001" LabelTitle="Main" />
<Command Name="cmdGroupRichFont" Id="1002" LabelTitle="Rich Font" />
<Command Name="cmdRichFont" Id="1003" Keytip="F" />
</Application.Commands>
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab CommandName="cmdTabMain">
<Group CommandName="cmdGroupRichFont" SizeDefinition="OneFontControl">
<FontControl CommandName="cmdRichFont" FontType="RichFont" />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
</Application>
More details on FontControl attributes can be found on MSDN.
Using FontControl – Code Behind
The following code shows the basic steps of using a ribbon FontControl which stays in sync with the selected text in a standard .NET RichTextBox control.
private Ribbon _ribbon;
private RibbonFontControl _richFont;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_richFont = new RibbonFontControl(_ribbon, (uint)RibbonMarkupCommands.cmdRichFont);
_richFont.OnExecute += new OnExecuteEventHandler(_richFont_OnExecute);
_richFont.OnPreview += new OnPreviewEventHandler(_richFont_OnPreview);
_richFont.OnCancelPreview += new OnCancelPreviewEventHandler(_richFont_OnCancelPreview);
}
- Setting RichTextBox properties when FontControl has changed:
void _richFont_OnExecute(PropertyKeyRef key, PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
// skip if selected font is not valid
if ((_richFont.Family == null) ||
(_richFont.Family.Trim() == string.Empty) ||
(_richFont.Size == 0))
{
return;
}
// prepare font style
FontStyle fontStyle = FontStyle.Regular;
if (_richFont.Bold == FontProperties.Set)
{
fontStyle |= FontStyle.Bold;
}
if (_richFont.Italic == FontProperties.Set)
{
fontStyle |= FontStyle.Italic;
}
if (_richFont.Underline == FontUnderline.Set)
{
fontStyle |= FontStyle.Underline;
}
if (_richFont.Strikethrough == FontProperties.Set)
{
fontStyle |= FontStyle.Strikeout;
}
// set selected font
richTextBox1.SelectionFont =
new Font(_richFont.Family, (float)_richFont.Size, fontStyle);
// set selected colors
richTextBox1.SelectionColor = _richFont.ForegroundColor;
richTextBox1.SelectionBackColor = _richFont.BackgroundColor;
// set subscript / superscript
switch (_richFont.VerticalPositioning)
{
case FontVerticalPosition.NotSet:
richTextBox1.SelectionCharOffset = 0;
break;
case FontVerticalPosition.SuperScript:
richTextBox1.SelectionCharOffset = 10;
break;
case FontVerticalPosition.SubScript:
richTextBox1.SelectionCharOffset = -10;
break;
}
}
Note: RichTextBox doesn’t support Subscript and Superscript natively. What it does support is setting the character offset, so this is what I use to simulate the required behavior.
- Adding support for preview while changing font family and size:
void _richFont_OnPreview(PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
PropVariant propChangesProperties;
commandExecutionProperties.GetValue(ref RibbonProperties.FontProperties_ChangedProperties, out propChangesProperties);
IPropertyStore changedProperties = (IPropertyStore)propChangesProperties.Value;
UpdateRichTextBox(changedProperties);
}
void _richFont_OnCancelPreview(PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
IPropertyStore fontProperties = (IPropertyStore)currentValue.PropVariant.Value;
UpdateRichTextBox(fontProperties);
}
private void UpdateRichTextBox(IPropertyStore propertyStore)
{
RibbonLib.FontPropertyStore fontPropertyStore = new RibbonLib.FontPropertyStore(propertyStore);
PropVariant propValue;
FontStyle fontStyle = richTextBox1.SelectionFont.Style;
string family = richTextBox1.SelectionFont.FontFamily.Name;
float size = richTextBox1.SelectionFont.Size;
if (propertyStore.GetValue(ref RibbonProperties.FontProperties_Family, out propValue) == HRESULT.S_OK)
{
family = fontPropertyStore.Family;
}
if (propertyStore.GetValue(ref RibbonProperties.FontProperties_Size, out propValue) == HRESULT.S_OK)
{
size = (float)fontPropertyStore.Size;
}
richTextBox1.SelectionFont = new Font(family, size, fontStyle);
}
Note: Only font family and font size should support preview since only they have attached combo boxes.
- Updating FontControl when text selection changes in RichTextBox:
private void richTextBox1_SelectionChanged(object sender, EventArgs e)
{
// update font control font
if (richTextBox1.SelectionFont != null)
{
_richFont.Family = richTextBox1.SelectionFont.FontFamily.Name;
_richFont.Size = (decimal)richTextBox1.SelectionFont.Size;
_richFont.Bold = richTextBox1.SelectionFont.Bold ?
FontProperties.Set : FontProperties.NotSet;
_richFont.Italic = richTextBox1.SelectionFont.Italic ?
FontProperties.Set : FontProperties.NotSet;
_richFont.Underline = richTextBox1.SelectionFont.Underline ?
FontUnderline.Set : FontUnderline.NotSet;
_richFont.Strikethrough = richTextBox1.SelectionFont.Strikeout ?
FontProperties.Set : FontProperties.NotSet;
}
else
{
_richFont.Family = string.Empty;
_richFont.Size = 0;
_richFont.Bold = FontProperties.NotAvailable;
_richFont.Italic = FontProperties.NotAvailable;
_richFont.Underline = FontUnderline.NotAvailable;
_richFont.Strikethrough = FontProperties.NotAvailable;
}
// update font control colors
_richFont.ForegroundColor = richTextBox1.SelectionColor;
_richFont.BackgroundColor = richTextBox1.SelectionBackColor;
// update font control vertical positioning
switch (richTextBox1.SelectionCharOffset)
{
case 0:
_richFont.VerticalPositioning = FontVerticalPosition.NotSet;
break;
case 10:
_richFont.VerticalPositioning = FontVerticalPosition.SuperScript;
break;
case -10:
_richFont.VerticalPositioning = FontVerticalPosition.SubScript;
break;
}
}
Update (18.11.2009): The updated version of the Ribbon class provides an implementation for IUICommandHandler, so the user doesn't need to implement Execute and UpdateProperty methods anymore.
Connect IUICommandHandler implementation with the helper class implementation:
public HRESULT Execute(uint commandId, ExecutionVerb verb, PropertyKeyRef key,
PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdRichFont:
_richFont.Execute(verb, key, currentValue, commandExecutionProperties);
break;
}
return HRESULT.S_OK;
}
public HRESULT UpdateProperty(uint commandId, ref PropertyKey key,
PropVariantRef currentValue, ref PropVariant newValue)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdRichFont:
_richFont.UpdateProperty(ref key, currentValue, ref newValue);
break;
}
return HRESULT.S_OK;
}
That’s it for now,
Arik Poznanski.
Windows Ribbon for WinForms library now supports DropDownColorPicker control.
The result of this post is a yet another sample, “11-DropDownColorPicker”, found on the project site.
DropDownColorPicker Control
The drop down color picker looks like this:
DropDownColorPicker Properties
Following is the list of properties which are unique for DropDownColorPicker control. The rest of the properties have been reviewed in previous posts.
- Color – The selected color.
Property Identifier: UI_PKEY_Color - ColorType – The type of selected color. Can be: NoColor, Automatic or RGB (meaning specific color).
Property Identifier: UI_PKEY_ColorType - AutomaticColorLabel – Defines the label for the “Automatic” color button.
Property Identifier: UI_PKEY_AutomaticColorLabel - MoreColorsLabel – Defines the label for the “More colors...” button.
Property Identifier: UI_PKEY_MoreColorsLabel - NoColorLabel – Defines the label for the “No color” button.
Property Identifier: UI_PKEY_NoColorLabel - RecentColorsCategoryLabel – Defines the label for the “Recent colors” category.
Property Identifier: UI_PKEY_RecentColorsCategoryLabel - StandardColorsCategoryLabel – Defines the label for the “Standard colors” category.
Property Identifier: UI_PKEY_StandardColorsCategoryLabel - ThemeColorsCategoryLabel – Defines the label for the “Theme colors” category.
Property Identifier: UI_PKEY_ThemeColorsCategoryLabel
Note: The different labels in the drop down color picker allows you to localize the control.
For more details on DropDownColorPicker control, check out Drop-Down Color Picker on MSDN.
Using DropDownColorPicker – Ribbon Markup
Commands and Views sections:
<?xml version='1.0' encoding='utf-8'?>
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
<Application.Commands>
<Command Name="cmdDropDownColorPickerThemeColors"
Id="1002"
LabelTitle="Theme Colors">
<Command.LargeImages>
<Image>Res/Colors32.bmp</Image>
</Command.LargeImages>
</Command>
</Application.Commands>
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab>
<Group>
<DropDownColorPicker CommandName="cmdDropDownColorPickerThemeColors"
ColorTemplate="ThemeColors"/>
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
</Application>
Using DropDownColorPicker – Code Behind
Initializing:
private Ribbon _ribbon;
private RibbonDropDownColorPicker _themeColors;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_themeColors = new RibbonDropDownColorPicker(_ribbon, (uint)RibbonMarkupCommands.cmdDropDownColorPickerThemeColors);
}
private void Form1_Load(object sender, EventArgs e)
{
_ribbon.InitFramework(this);
InitDropDownColorPickers();
}
private void InitDropDownColorPickers()
{
// common properties
_themeColors.Label = "Theme Colors";
_themeColors.OnExecute += new OnExecuteEventHandler(_themeColors_OnExecute);
// set labels
_themeColors.AutomaticColorLabel = "My Automatic";
_themeColors.MoreColorsLabel = "My More Colors";
_themeColors.NoColorLabel = "My No Color";
_themeColors.RecentColorsCategoryLabel = "My Recent Colors";
_themeColors.StandardColorsCategoryLabel = "My Standard Colors";
_themeColors.ThemeColorsCategoryLabel = "My Theme Colors";
// set colors
_themeColors.ThemeColorsTooltips = new string[] { "yellow", "green", "red", "blue" };
_themeColors.ThemeColors = new Color[] { Color.Yellow, Color.Green, Color.Red, Color.Blue };
}
Update (18.11.2009): The updated version of the Ribbon class provides an implementation for IUICommandHandler, so the user doesn't need to implement Execute and UpdateProperty methods anymore.
Connect IUICommandHandler implementation with the helper classes implementations:
public HRESULT Execute(uint commandId, ExecutionVerb verb, PropertyKeyRef key,
PropVariantRef currentValue,
IUISimplePropertySet commandExecutionProperties)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerThemeColors:
_themeColors.Execute(verb, key, currentValue, commandExecutionProperties);
break;
}
return HRESULT.S_OK;
}
public HRESULT UpdateProperty(uint commandId, ref PropertyKey key,
PropVariantRef currentValue, ref PropVariant newValue)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdDropDownColorPickerThemeColors:
_themeColors.UpdateProperty(ref key, currentValue, ref newValue);
break;
}
return HRESULT.S_OK;
}
Respond to selected color event:
void _themeColors_OnExecute(PropertyKeyRef key, PropVariantRef currentValue, IUISimplePropertySet commandExecutionProperties)
{
MessageBox.Show("Selected color is " + _themeColors.Color.ToString());
}
Windows Ribbon for WinForms Library Update
Warning: Internal details ahead. Not related to DropDownColorPicker in any way.
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 depends 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).
That’s it for now,
Arik Poznanski.
CheckBox and ToggleButton
In short, I’ve added support for CheckBox and ToggleButton ribbon controls.
A new sample, named “10-CheckBox” has been added to the project site. The result look like this:
Using CheckBox and ToggleButton – Ribbon Markup
Commands and Views sections:
<?xml version='1.0' encoding='utf-8'?>
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
<Application.Commands>
<Command Name="cmdToggleButton"
Id="1002"
LabelTitle="Toggle Button">
<Command.LargeImages>
<Image>Res/Open32.bmp</Image>
</Command.LargeImages>
<Command.SmallImages>
<Image>Res/Open16.bmp</Image>
</Command.SmallImages>
</Command>
<Command Name="cmdCheckBox"
Id="1003"
LabelTitle="Check Box">
<Command.LargeImages>
<Image>Res/Save32.bmp</Image>
</Command.LargeImages>
<Command.SmallImages>
<Image>Res/Save16.bmp</Image>
</Command.SmallImages>
</Command>
</Application.Commands>
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab>
<Group>
<ToggleButton CommandName="cmdToggleButton" />
</Group>
<Group CommandName="cmdGroupCheckBox">
<CheckBox CommandName="cmdCheckBox" />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
</Application>
Using CheckBox and ToggleButton – Code Behind
Initializing:
private Ribbon _ribbon;
private RibbonToggleButton _toggleButton;
private RibbonCheckBox _checkBox;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_toggleButton = new RibbonToggleButton(_ribbon, (uint)RibbonMarkupCommands.cmdToggleButton);
_checkBox = new RibbonLib.Controls.RibbonCheckBox(_ribbon, (uint)RibbonMarkupCommands.cmdCheckBox);
_button.OnExecute += new OnExecuteEventHandler(_button_OnExecute);
}
Connect IUICommandHandler implementation with the helper classes implementations: [If this the first time you see this, you should really check the previous posts..]
public HRESULT Execute(uint commandId, RibbonLib.Interop.UI_ExecutionVerb verb,
ref PropertyKey key, ref PropVariant currentValue,
IUISimplePropertySet commandExecutionProperties)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdToggleButton:
_toggleButton.Execute(verb, ref key, ref currentValue,
commandExecutionProperties);
break;
case (uint)RibbonMarkupCommands.cmdCheckBox:
_checkBox.Execute(verb, ref key, ref currentValue,
commandExecutionProperties);
break;
}
return HRESULT.S_OK;
}
public HRESULT UpdateProperty(uint commandId, ref PropertyKey key,
ref PropVariant currentValue,
ref PropVariant newValue)
{
switch (commandId)
{
case (uint)RibbonMarkupCommands.cmdToggleButton:
_toggleButton.UpdateProperty(ref key, ref currentValue, ref newValue);
break;
case (uint)RibbonMarkupCommands.cmdCheckBox:
_checkBox.UpdateProperty(ref key, ref currentValue, ref newValue);
break;
}
return HRESULT.S_OK;
}
Update (18.11.2009): The updated version of the Ribbon class provides an implementation for IUICommandHandler, so the user doesn't need to implement Execute and UpdateProperty methods anymore.
Get / Set CheckBox status:
void _button_OnExecute(ref PropertyKey key, ref PropVariant currentValue,
IUISimplePropertySet commandExecutionProperties)
{
MessageBox.Show("checkbox check status is: " + _checkBox.BooleanValue.ToString());
}
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. Also, it has nothing to do with the checkbox feature.
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 ExeciteEventsProvider 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 has 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 exists, 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
That’s it for now,
Arik Poznanski.