This series of CodeProject articles is based on a series of posts I've first published on my blog.
ComboBox Control
A ribbon ComboBox control is basically the normal ComboBox control that we all love, but with the additional feature of dividing the items into categories. A category is not an item and cannot be selected from the ComboBox. It is only used to organize the items.
ComboBox Properties
Every ribbon control has properties that define the way it looks and behaves. Here is a quick review of the ComboBox properties, divided into logical groups:
ComboBox Value Related Properties
ItemsSource
- The list of ComboBox items. It is exposed as an IUICollection
where every element in the collection is of type IUISimplePropertySet
. More on this later. Property identifier: UI_PKEY_ItemsSource
.Categories
- The list of categories. Also exposed as an IUICollection
of IUISimplePropertySet
elements. Property identifier: UI_PKEY_Categories
.SelectedItem
- The index of the selected item in the ComboBox. If nothing is selected, this returns UI_Collection_InvalidIndex
, which is a fancy way to say -1. Property identifier: UI_PKEY_SelectedItem
.String Value
- The current string in the ComboBox. This can be a string that isn't one of the possible items in the ComboBox, in case the ComboBox has IsEditable
set to true
. Property identifier: UI_PKEY_StringValue
ComboBox Appearance Related Properties
- Representative string - A string that represents the common value for the ComboBox. This is used to calculate the width of the ComboBox, so you should set here the longest string you forecast. Note that it doesn't have to be an actual value, it can also be: “XXXXXXXXâ€. Property identifier:
UI_PKEY_RepresentativeString
.
Common Appearance and Image Properties
See these sections at Windows Ribbon for WinForms, Part 7 - Spinner
Using ComboBox - Ribbon Markup
As always, a command should be defined:
<Command Name="cmdComboBox2" Id="1019" />
The views section:
<Application.Views>
<Ribbon>
<Ribbon.Tabs>
<Tab>
<Group>
<ComboBox CommandName="cmdComboBox2"
IsAutoCompleteEnabled="true"
IsEditable="true"
ResizeType="VerticalResize" />
</Group>
</Tab>
</Ribbon.Tabs>
</Ribbon>
</Application.Views>
ComboBox attributes:
CommandName
- Name of the command attached to this ComboBox.IsAutoCompleteEnabled
- Flag that indicates whether to complete the words as you write.IsEditable
- Flag that indicates whether to allow free writing in the ComboBox.ResizeType
- Allow resize of the ComboBox. Can be NoResize
or VerticalResize
.
Using ComboBox - Code-Behind
In a similar way to the spinner control, I've created a helper classes that encapsulates the interaction between the ComboBox and the ribbon framework. To use the ComboBox, create a RibbonComboBox
instance, passing to the constructor the Ribbon instance and the command ID of the ComboBox:
private Ribbon _ribbon;
private RibbonComboBox _comboBox2;
public Form1()
{
InitializeComponent();
_ribbon = new Ribbon();
_comboBox2 = new RibbonComboBox(_ribbon,
(uint)RibbonMarkupCommands.cmdComboBox2);
_comboBox2.RepresentativeString = "XXXXXXXXXXX";
}
Note: We set the RepresentativeString
property before initializing the ribbon framework. This is because for some reason, the framework reads this property only once, when the ribbon is initialized. This means that if you change it after initialization, it will have no effect since the framework doesn't read this property anymore. By the way, according to the current documentation of the ribbon framework, this property is not part of the ComboBox, but as mentioned earlier, this property controls the width of the ComboBox.
In the next code snippet, you can see how to use another helper class named GalleryItemPropertySet
. This class represents a container for properties of a single element in an IUICollection
.
Adding categories and items to the ComboBox is done like this:
private void Form1_Load(object sender, EventArgs e)
{
_ribbon.InitFramework(this);
_comboBox2.Label = "Advanced Combo";
IUICollection categories2 = _comboBox2.Categories;
categories2.Clear();
categories2.Add(new GalleryItemPropertySet() { Label="Category 1", CategoryID=1 });
categories2.Add(new GalleryItemPropertySet() { Label="Category 2", CategoryID=2 });
IUICollection itemsSource2 = _comboBox2.ItemsSource;
itemsSource2.Clear();
itemsSource2.Add(new GalleryItemPropertySet() { Label="Label 1", CategoryID=1 });
itemsSource2.Add(new GalleryItemPropertySet() { Label="Label 2", CategoryID=1 });
itemsSource2.Add(new GalleryItemPropertySet() { Label="Label 3", CategoryID=2 });
}
Note: Adding items and categories can be done only after the Ribbon Framework has been initialized.
Finally, you must connect the IUICommandHandler.UpdateProperty
method with the implementation of this method in our RibbonComboBox
class:
public HRESULT UpdateProperty(uint commandId, ref PropertyKey key,
PropVariantRef currentValue, ref PropVariant newValue)
{
if (commandId == (uint)RibbonMarkupCommands.cmdComboBox2)
{
_comboBox2.UpdateProperty(ref key, currentValue, ref newValue);
}
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 the Execute
and UpdateProperty
methods anymore.
IUICollection Events
Objects that implement the IUICollection
interface usually expose an OnChanged
event that is called when the collection has changed due to: Insert item, Remove item, Replace item, Reset collection.
This event is exposed using the standard COM events mechanism, namely: IConnectionPointContainer
, IConnectionPoint
, and Advise()
.
To help the user to avoid these issues altogether, I've created the UICollectionChangedEvent
class, which attaches to a given IUICollection
and exposes the OnChanged
event as a normal .NET event.
Following is an example of using it:
private RegisterEvent()
{
_uiCollectionChangedEvent = new UICollectionChangedEvent();
_uiCollectionChangedEvent.Attach(_comboBox1.ItemsSource);
_uiCollectionChangedEvent.OnChanged +=
new UICollectionChangedEvent.OnChangedEventHandler(_ChangedEvent_OnChanged);
}
void _ChangedEvent_OnChanged(UI_CollectionChange action,
uint oldIndex, object oldItem,
uint newIndex, object newItem)
{
MessageBox.Show("Got OnChanged event. Action = " + action.ToString());
}
Note: There is no OnChanged
event for the ComboBox. Only for IUICollection
, which is completely different.
Update (27.10.2009): The ComboBox itself has three events: Execute
, Preview
, and CancelPreview
. The Execute
event can be used as a "Selected Change" event. See this future post.
Summary
You can find a working sample that demonstrates using a ComboBox control at Windows Ribbon for WinForms under the sample "06-ComboBox".
That's it for now.