Monday, February 8, 2010

SharePoint 2010 Ribbon Customization - Adding FlyoutAnchor control

In the previous posts we’ve described the way to add custom buttons, groups and tabs to the SharePoint 2010 Ribbon. In this post we’ll show the way of adding FlyoutAnchor control to the Ribbon – the control representing pull-down menu items list.

It is possible to deploy all the menu items either in FlyoutAnchor declaration or construct them dynamically with JavaScript. Here are the samples of both models.

FlyoutAnchor with static menu items

Here is the example of adding custom FlyoutAnchor control with static menu items:

<CommandUIDefinition Location="[Exisiting_Group_ID].Controls._children">
  <FlyoutAnchor
    Id="[Your_FlyoutAnchor_ID]"
    Command="[Your_FlyoutAnchor_Command_Name]"
    Sequence="10"
    Image32by32="/_layouts/images/RibbonCustomization/images32x32.png"
    Image32by32Top="0"
    Image32by32Left="-32"
    LabelText="FlyoutAnchor Static"
    TemplateAlias="o1"
    ToolTipTitle="FlyoutAnchor Static"
    ToolTipDescription="FlyoutAncor with static menu items">
    <Menu Id="[Your_FlyoutAnchor_ID].Menu">
      ...
      <MenuSection
        Id="[Section_ID]"
        Sequence="10"
        DisplayMode="Menu16">
        <Controls Id="[Section_ID].Controls">
          ...
          <Button
            Id="[Button_ID]"
            Command="[StaticButtonCommand_Name]"
            Sequence="10"
            Alt="Btn 1"
            LabelText="Static Button 1"/>
          ...
        </Controls>
      </MenuSection>
      ...
    </Menu>
  </FlyoutAnchor>
</CommandUIDefinition>

In order to add custom FlyoutAnchor control to the Ribbon you should declare it with all its menu sub-items. There is a way to split menu items into several groups by putting your menu items (buttons) to different MenuSection xml tags. The value of DisplayMode attribute (Menu16/Menu32) shows the size of menu items images – large or small.

If you specify the Command attribute of xml FlyoutAnchor tag, be sure to register this command, otherwise you won’t be able to force menu items to pull down.

If you need one of the menu items to have sub-items, you have to add a FlyoutAnchor xml declaration as a menu item control to the menu section, like you do with usual buttons.

FlyoutAnchor with dynamic menu items

In some cases you have to populate FlyoutAnchor menu items dynamically. Here is the example of adding FlyoutAnchor with dynamic menu items:

<CommandUIDefinition Location="[Exisiting_Group_ID].Controls._children">
  <FlyoutAnchor
    Id="[Your_FlyoutAnchor_ID]"
    Command="[Your_FlyoutAnchor_Command_Name]"
    Sequence="10"
    Image16by16="/_layouts/images/RibbonCustomization/images16x16.png"
    Image16by16Top="0"
    Image16by16Left="-16"
    Image32by32="/_layouts/images/RibbonCustomization/images32x32.png"
    Image32by32Top="0"
    Image32by32Left="-32"
    LabelText="FlyoutAnchor Dymamic"
    TemplateAlias="o1"
    PopulateDynamically="true"
    PopulateOnlyOnce="false"
    PopulateQueryCommand="[Populate_Dymamic_Menu_Items_Query_Command_Name]"
    ToolTipTitle="FlyoutAnchor Dymamic"
    ToolTipDescription="FlyoutAnchor wit dymamic menu items" />
</CommandUIDefinition>

There are three important attributes in the FlyoutAnchor node:

  1. PopulateDynamically – this attribute has to be set to "true";
  2. PopulateOnlyOnce – this Boolean attribute tells if menu items should be constructed every time the FlyoutAnchor is being pulled down. Use "false" to make them build every time;
  3. and PopulateQueryCommand – the name of command which is being invoked every time when the menu items have to be shown (once if PopulateOnlyOnce attribute value is set to "true").

The PopulateQueryCommand has to set PopulationXML value to command properties. In order to do this you have to register this command on the server side (see Server-side command handling post). Here is the example:

commands.Add(new SPRibbonCommand(
                    "[Populate_Dymamic_Menu_Items_Query_Command_Name]",
                    "properties.PopulationXML = GetDynamicMenuXml()"));
The GetDynamicMenuXml JavaScript function mentioned here should construct exactly the same XML, you would use in case of adding menu items declaratively. Here is the example:
function GetDynamicMenuXml() {
    var dynamicMenuXml =
    '<Menu Id="[Your_FlyoutAnchor_ID].Menu">'
    + '<MenuSection Id="[Section_ID]" DisplayMode="Menu16">'
    + '<Controls Id="[Section_ID].Controls">';
    var itemsNumber = Math.floor(Math.random()*10) + 1;
    for (i = 0; i < itemsNumber; i++) {
        var buttonXML = String.format(
           '<Button Id="DynamicButton{0}" '
           + 'Command="[Dynamic_Button_Command_Name]" '
           + 'MenuItemId="{0}" '
           + 'LabelText="DynamicButton {0}" '
           + 'ToolTipTitle="Dynamic Button" '
           + 'ToolTipDescription="Dynamic Button" />',
           i);
        dynamicMenuXml += buttonXML;
    }
    dynamicMenuXml += '</Controls>' + '</MenuSection>' + '</Menu>';
    return dynamicMenuXml;
}

If you have to handle all the menu items commands with one command, you can bypass kind of "unique argument" to this command. You should use MenuItemId button attribute, and then it will be available on the command handler. Here is the example of CommandUIHandler declaration:

<CommandUIHandler
  Command="[Dynamic_Button_Command_Name]"
  CommandAction="javascript:alert('Dynamic Button ' + arguments[2].MenuItemId + ' clicked.');"
  EnabledScript="true" />

The same approach can be applied for extending the Ribbon with DropDown controls. Those can have static/dynamic items declaration as well.

1 comment:

  1. How do you replace a n existing flyoutanchor menuitems with your own optins?

    ReplyDelete