Click here to Skip to main content
Click here to Skip to main content

Windows Ribbon for WinForms, Part 14 – FontControl

By , 16 Mar 2010
Rate this:
Please Sign up or sign in to vote.

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.

image

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

image

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:

<?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);
    }
  • 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 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.

  • 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.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Arik Poznanski
Software Developer (Senior) Verint
Israel Israel
Arik Poznanski is a senior software developer at Verint. He completed two B.Sc. degrees in Mathematics & Computer Science, summa cum laude, from the Technion in Israel.
 
Arik has extensive knowledge and experience in many Microsoft technologies, including .NET with C#, WPF, Silverlight, WinForms, Interop, COM/ATL programming, C++ Win32 programming and reverse engineering (assembly, IL).
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionAdditional Buttons next to a FontControl PinmemberPhrankPhoebius2-May-12 23:59 
Generalcan't compile. Pinmemberjosephlawrencecarpio16-Mar-10 10:52 
GeneralRe: can't compile. PinmemberMDL=>Moshu16-Mar-10 11:35 
GeneralRe: can't compile. PinmemberArik Poznanski16-Mar-10 23:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 16 Mar 2010
Article Copyright 2010 by Arik Poznanski
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid