Windows Ribbon for WinForms, Part 14 – FontControl

14 בנובמבר 2009

6 תגובות

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.


image 


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

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



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

kick it on DotNetKicks.com Shout it

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. (*) שדות חובה מסומנים

6 תגובות

  1. Wuhi17 בנובמבר 2009 ב 12:59

    nice!
    is it also possible to use these buttongroups with own commands?

    להגיב
  2. arik17 בנובמבר 2009 ב 13:43

    Can you clarify what do you mean by "buttongroups"?

    להגיב
  3. Wuhi17 בנובמבר 2009 ב 15:08

    hi,
    i think in the ribbon framework these control is named "Minitoolbar" (http://msdn.microsoft.com/en-us/library/dd371705%28VS.85%29.aspx)

    is it possible to create these kind of buttons with your wrapper?

    להגיב
  4. arik17 בנובמבר 2009 ב 15:27

    Minitoolbar is part of the "Context Popup" feature [http://msdn.microsoft.com/en-us/library/dd940493(VS.85).aspx]

    This feature is not available yet, but is planned for a future post.

    להגיב
  5. Anonymous2 בנובמבר 2010 ב 23:34

    Just wondering, when I click the More Fonts button, which is under the font list in the drop down menu, the Fonts directory (C:\Windows\Fonts) opens. This is not very user-friendly and it doesn't serve any purpose. Is it possible to change this to show a font dialog or just to remove that button?

    Thanks.

    להגיב
  6. arik3 בנובמבר 2010 ב 1:32

    This is part of the FontControl implementation.
    I didn't find an easy way to remove it, but I suggest you go over the MSDN documentation of the FontControl.

    להגיב