Windows Ribbon for WinForms, Part 14 – FontControl





5.00/5 (10 votes)
In this article, I'll present how to use the ribbon font control.
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 typeIPropertyStore
, and holds all the font specific properties, likeSize
,Bold
,Underline
, etc. In theFontControl
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. TheFontControl
doesn't expose it, but provides it as one of the parameters in theExecute
/Preview
/CancelPreview
events. For example, if you click on the "Bold" button, theExecute
event will be called and this property will contain only theBold
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 ifForegroundColorType
is set toRGB
. TheFontControl
helper class exposes this property as a .NETColor
, and internally handles the conversion to and from theCOLORREF
structure. Property Identifier:UI_PKEY_FontProperties_ForegroundColor
.ForegroundColorType
- The text color type. Valid values areRGB
andAutomatic
. IfRGB
is selected, the user should get the color from theForegroundColor
property. IfAutomatic
is selected, the user should useSystemColors.WindowText
. TheFontControl
helper class doesn't expose theForegroundColorType
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 ifBackgroundColorType
is set toRGB
. TheFontControl
helper class exposes this property as a .NETColor
, and internally handles the conversion to and from theCOLORREF
structure. Property Identifier:UI_PKEY_FontProperties_BackgroundColor
.BackgroundColorType
- The background color type. Valid values areRGB
andNoColor
. IfRGB
is selected, the user should get the color from theBackgroundColor
property. IfNoColor
is selected, the user should useSystemColors.Window
. TheFontControl
helper class doesn't expose theForegroundColorType
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 theChangedProperties
property, and is not exposed by theFontControl
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 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.
- Initializing:
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);
}
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.
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.
FontControl
when the text selection changes in the 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 the Execute
and UpdateProperty
methods anymore.
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.