Windows Ribbon for WinForms, Part 12 – CheckBox and ToggleButton

1 בנובמבר 2009

אין תגובות

CheckBox and ToggleButton
In short, I’ve added support for CheckBox and ToggleButton ribbon controls.
A new sample, named “10-CheckBox” has been added to the project site. The result look like this:

image

Using CheckBox and ToggleButton – 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="cmdToggleButton"
             Id="1002"
             LabelTitle="Toggle Button">
      <Command.LargeImages>
        <Image>Res/Open32.bmp</Image>
      </Command.LargeImages>
      <Command.SmallImages>
        <Image>Res/Open16.bmp</Image>
      </Command.SmallImages>
    </Command>

    <Command Name="cmdCheckBox"
             Id="1003"
             LabelTitle="Check Box">
      <Command.LargeImages>
        <Image>Res/Save32.bmp</Image>
      </Command.LargeImages>
      <Command.SmallImages>
        <Image>Res/Save16.bmp</Image>
      </Command.SmallImages>
    </Command>

  </Application.Commands>

  <Application.Views>
    <Ribbon>
      <Ribbon.Tabs>
        <Tab>
          <Group>
            <ToggleButton CommandName="cmdToggleButton" />
          </Group>
          <Group CommandName="cmdGroupCheckBox">
            <CheckBox CommandName="cmdCheckBox" />
          </Group>
        </Tab>
      </Ribbon.Tabs>
    </Ribbon>
  </Application.Views>
</Application>

Using CheckBox and ToggleButton – Code Behind
Initializing:

private Ribbon _ribbon;
private RibbonToggleButton _toggleButton;
private RibbonCheckBox _checkBox;

public Form1()
{
    InitializeComponent();

    _ribbon = new Ribbon();
    _toggleButton = new RibbonToggleButton(_ribbon, (uint)RibbonMarkupCommands.cmdToggleButton);
    _checkBox = new RibbonLib.Controls.RibbonCheckBox(_ribbon, (uint)RibbonMarkupCommands.cmdCheckBox);

    _button.OnExecute += new OnExecuteEventHandler(_button_OnExecute);
}

Connect IUICommandHandler implementation with the helper classes implementations: [If this the first time you see this, you should really check the previous posts..]

public HRESULT Execute(uint commandId, RibbonLib.Interop.UI_ExecutionVerb verb,
                        ref PropertyKey key, ref PropVariant currentValue,
                        IUISimplePropertySet commandExecutionProperties)
 {
     switch (commandId)
     {
         case (uint)RibbonMarkupCommands.cmdToggleButton:
             _toggleButton.Execute(verb, ref key, ref currentValue,
                                   commandExecutionProperties);
             break;

         case (uint)RibbonMarkupCommands.cmdCheckBox:
             _checkBox.Execute(verb, ref key, ref currentValue,
                               commandExecutionProperties);
             break;
     }

     return HRESULT.S_OK;
 }

 public HRESULT UpdateProperty(uint commandId, ref PropertyKey key,
                               ref PropVariant currentValue,
                               ref PropVariant newValue)
 {
     switch (commandId)
     {
         case (uint)RibbonMarkupCommands.cmdToggleButton:
             _toggleButton.UpdateProperty(ref key, ref currentValue, ref newValue);
             break;

         case (uint)RibbonMarkupCommands.cmdCheckBox:
             _checkBox.UpdateProperty(ref key, ref currentValue, ref newValue);
             break;
     }

     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 Execute and UpdateProperty methods anymore.

Get / Set CheckBox status:

void _button_OnExecute(ref PropertyKey key, ref PropVariant currentValue,
                       IUISimplePropertySet commandExecutionProperties)
{
    MessageBox.Show("checkbox check status is: " +  _checkBox.BooleanValue.ToString());
}

Windows Ribbon for WinForms Library Internal Design Issues
Warning: the rest of this post is extremely boring. It discusses internal details of my ribbon library implementation. This doesn’t change anything for the user of the library. Also, it has nothing to do with the checkbox feature.

So now that I’m the only one left, I can discuss some internal details of the library. I’ve just made a major refactoring of the ribbon library.

The ribbon library is composed of:

  • Windows Ribbon Framework API wrappers
  • Main ribbon class
  • Helper classes for different ribbon controls, such as Button, ComboBox, DropDownGallery etc.

In the old version of the RibbonLib, the controls helper classes had lots of duplicated code. For instance, each control that had images attached to it (LargeImage, SmallImage, … properties) needed to handle those images in the same way (manipulating internal variables, notifying the parent ribbon that an image has invalidated etc.). Now, I don’t know about you, but whenever I copy-paste code I always get this strange feeling that something is wrong. So after several sample projects I couldn’t take it anymore and decided to redesign this section.

What I’ve done was encapsulate common code in classes, so they can be reused in several controls without duplicating code.

So now every ribbon control is composed from several properties providers (like ImagePropertiesProvider and TooltipPropertiesProvider) and events providers (like ExeciteEventsProvider and PreviewEventsProvider).

Note: The following sentence is hard, but there is an example right after, so be strong.

Each provider component has its own interface which the using-control also implements by delegating the execution to the component.

For example, I have an ImagePropertiesProvider class that implements the interface IImagePropertiesProvider, which exposes 4 image properties (LargeImage, SmallImage, ..).
In my Button helper class I create a member variable of type ImagePropertiesProvider and make the Button class also implement IImagePropertiesProvider by calling the corresponding methods on the member variable.

This is one of those cases where multiple inheritance was really missing. As a substitute, what I did was used multiple inheritance of interfaces, aggregation and delegation pattern. So the controls still has some duplicated code (the delegation code) but this code is really simple and has no logic in it.

Also, each ribbon control has an Execute and UpdateProperty methods it needs to implement according to the properties and events it exposes. So I’ve made a general implementation which resided in the BaseRibbonControl class that search the implementation of a property or event inside one of the registered providers, thus simplifying this code section in every control (now it doesn’t exists, the simplest way I know).

The results of all these changes are:

  • Shorter code with less duplications.
  • Developing of new helper classes is extremely simple.
  • Cool class diagrams..

Properties Providers Class Diagram

Properties Providers Class Diagram

Events Providers Class Diagram

Events Providers Class Diagram

Ribbon Controls Class Diagram

Ribbon Controls Class Diagram

That’s it for now,
Arik Poznanski.

kick it on DotNetKicks.com Shout it

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

כתיבת תגובה

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