This series of CodeProject articles is based on a series of posts I've first published on my blog.
The Windows Ribbon for WinForms library now supports the 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 the font family, size, colors, and related effects. It has three types, each exposing a little more functionality than 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 the 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 than 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 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 exposes this property as a .NET Color
, and internally handles the conversion to and from the 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 exposes this property as a .NET Color
, and internally handles the conversion to and from the 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., returns the correct color according to the type property). Property Identifier: UI_PKEY_FontProperties_BackgroundColorType
.DeltaSize
- Indicates 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:
='1.0'='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 the 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)
{
if ((_richFont.Family == null) ||
(_richFont.Family.Trim() == string.Empty) ||
(_richFont.Size == 0))
{
return;
}
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;
}
richTextBox1.SelectionFont =
new Font(_richFont.Family, (float)_richFont.Size, fontStyle);
richTextBox1.SelectionColor = _richFont.ForegroundColor;
richTextBox1.SelectionBackColor = _richFont.BackgroundColor;
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 the text selection changes in the RichTextBox
:
private void richTextBox1_SelectionChanged(object sender, EventArgs e)
{
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;
}
_richFont.ForegroundColor = richTextBox1.SelectionColor;
_richFont.BackgroundColor = richTextBox1.SelectionBackColor;
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 the Execute
and UpdateProperty
methods anymore.
Connect the 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.