Wednesday, January 6, 2010

SharePoint 2010 Ribbon Customization - controls and commands deployment

Introduction

One of the most valuable interface changes provided in SharePoint 2010 is the new Ribbon. This contextual interface allows users to execute any action related to ribbon controls depending upon the context the user is currently dealing with. The SharePoint 2010 API allows developers to extend and customize the ribbon using SharePoint features on site/site collection level. This article shows the way how to do that.

There are several types of controls which can be deployed to SharePoint Ribbon:

  • Button,
  • CheckBox,
  • DropDown,
  • FlyoutAnchor
  • and ToggleButton.


These controls can be collected for usability purposes to containers such as Group and Tab. Therefore it is possible to add controls with custom functionality not only to existing containers, but deploy new tabs and groups, and then and add necessary controls to them.

Any ribbon customization should be mounted within xml in feature declaration. The special xml tag exists for this purpose. Here is the example how it usually looks like:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    ...<br />    <CustomAction
      Id="[Your_custom_action_ID]"
      Location="CommandUI.Ribbon"
      Title="Custom Action title here">
        <CommandUIExtension>
            <CommandUIDefinitions>
            ...
            </CommandUIDefinitions>
            <CommandUIHandlers>
            ...
            </CommandUIHandlers>
        </CommandUIExtension>
    </CustomAction>
    ...
</Elements>

The CustomAction xml tag should have its Id in corresponding attribute – unique text value. The value for Location attribute should always be set to "CommandUI.Ribbon", independently on what kind of ribbon customization it is created for. The CommandUIDefinitions tag should contain CommandUIDefinition child tags declaring all controls or containers which should be created (i.e. buttons, groups, tabs, etc.).

The CommandUIHandlers tag can contain commands declarations for registered controls, so some JavaScript code can be executed. It is not necessary to register all commands in custom action – it can be done on server (webpart/page code-behind). The way how to do it will be described in next posts.

IMPORTANT. If you have deployed some ribbon customization xml and later have to provide some changes into it (change JavaScript for command handler, change FlyoutAnchor control sub-items etc.) it might be necessary to change the Feature ID for SharePoint feature your customization belongs to. For simple modifications (i.e. changing button titles, image URLs etc.) this is not necessary, but if you change the Feature ID every time you change anything in xml, it might save a lot of time and effort.

Adding custom button to existing group

Here is the example of declaring button control to be added to the ribbon which should be added to CommandUIDefinitions xml node:

<CommandUIDefinition Location="[Existing_Group_ID].Controls._children">
  <Button<br />    Id="[Your_Button_ID]"
    Sequence="20"
    Command="[Your_Command_ID]"
    LabelText="Custom Button Label"
    Alt="Custom Button alt text"
    Image16by16="/_layouts/images/RibbonCustomization/images16x16.png"
    Image16by16Top="-16"
    Image16by16Left="-32"
    Image32by32="/_layouts/images/RibbonCustomization/images32x32.png"
    Image32by32Top="0"
    Image32by32Left="-64"
    TemplateAlias="o1"
    ToolTipTitle="Custom Button"
    ToolTipDescription="Executes custom action" />
</CommandUIDefinition>

The Location attribute of CommandUIDefinition xml element should be constructed in the following way: [Existing_Group_ID].Controls._children. You can find group’s ID in its declaration xml or using IE Dev Toolbar (the Group node is rendered as <li id="[TabID]">…</li> html tag).

It is possible to add some image to the button. For this purpose you should specify image URLs in Image16by16 and Image32by32 attributes (Image16by16 image appears if group size is too small for 32x32 image). Attributes i.e. Image32by32Top and Image32by32Left are used to set top/left margins for the images.

To perform some action on deployed control the CommandUIHandler xml element should be added to CommandUIHandlers xml node, and its name should be set to the Command attribute of the control (you don’t need to do it in case if you add command handler programmatically). Here is the example:

<CommandUIHandler
  Command="[Your_Command_ID]"
  CommandAction="javascript:alert('Button clicked.');"
  EnabledScript="true" />

Any ribbon control should have TemplateAlias attribute. Its value determines the location of the control inside the group (like web part zones in page layout) and depends upon the group’s template the control is being added to. To determine what value should be used here, you should check the group’s Template attribute, than find corresponding GroupTemplate template declaration xml tag (predefined templates can be found in c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\GLOBAL\XML\CMDUI.xml file) and choose the TemplateAlias attribute value of necessary ControlRef xml sub-node.

Adding custom group to existing tab

Here is the example of adding new group to existing tab:

<CommandUIDefinition Location="[ExistingTabID].Scaling._children">
  <MaxSize 
    Id="[Your_Group_ID].MaxSize"
    GroupId="[Your_Group_ID]"
    Size="LargeLarge" 
    Sequence="10" />
</CommandUIDefinition>
<CommandUIDefinition Location="[ExistingTabID].Scaling._children">
    <Scale
    Id="[Your_Group_ID].Popup"
    GroupId="[Your_Group_ID]"
    Size="Popup"
  Sequence="20" />
</CommandUIDefinition>
<CommandUIDefinition Location="[ExistingTabID].Groups._children">
  <Group
    Id="[Your_Group_ID]"
    Sequence="1"
    Title="Custom Group"
    Template="Ribbon.Templates.Flexible2"
    Image32by32Popup="/_layouts/images/RibbonCustomization/images32x32.png"
    Image32by32PopupTop="-128"
    Image32by32PopupLeft="-192">
      <Controls Id="Ribbon.WebPartPage.CustomGroup.Controls">
          ...
      </Controls>
  </Group>
</CommandUIDefinition>

In this sample you should pay attention to the following:

  1. Three different CommandUIDefinition xml nodes should be created: for deploying MaxSize, Scale and Group nodes; MaxSize and Scale nodes should reference to the group which is currently being declared (using GroupId attribute); the Size attributes should be based on the group template. If no MaxSize and Scale declarations for new group is created, on incorrect values of Size attributes are specified, the group won’t be visible or no controls should be shown in it;
  2. The Location attributes of CommandUIDefinition xml elements should be constructed in the following way: [ExistingTabID].Scaling._children – for MaxSize and Scale nodes; [ExistingTabID].Groups._children – for Group node;
  3. All controls for this group can be declared directly in the Controls node inside the group declaration xml.

Adding custom tab to ribbon

Here is the example of declaring custom ribbon tab:

<CommandUIDefinition Location="Ribbon.Tabs._children">
  <Tab
    Description="Custom Tab"
    Id="[Your_Tab_ID]"
    Sequence="1"
    Title="Custom Tab">
      <Scaling Id="[Your_Tab_ID].Scaling">
      ...
      </Scaling>
      <Groups Id="[Your_Tab_ID].Groups">
      ...
    </Groups>
  </Tab>
</CommandUIDefinition>

In this sample you should pay attention to the following:

  1. The Location attribute of CommandUIDefinition xml element should be exactly the following: Ribbon.Tabs._children;
  2. All inner groups and scaling xml nodes for them can be declared directly in Scaling and Groups xml nodes inside the tab declaration node respectively.
    You should make your tab visible in the page you are working with. This should be done programmatically in either page of Web Part classes. Here is the code sample with such functionality:
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    var ribbon = SPRibbon.GetCurrent(Page);
    if (ribbon != null)
    {
        ribbon.Minimized = false;
        ribbon.CommandUIVisible = true;
        const string initialTabId = "RibbonCustomization.CustomTab";
        if(!ribbon.IsTabAvailable(initialTabId))
            ribbon.MakeTabAvailable(initialTabId);
        ribbon.InitialTabId = initialTabId;
    }
}

The code line #13 will make the tab active by default when the page is opened.

In the next post it will be shown how to add controls’ command handlers programmatically. It might be helpful if you have to construct command script/enabled script JavaScript code for your ribbon controls in runtime or to handle ribbon commands on server.

12 comments:

  1. Great Thanks, phrase "it might be necessary to change the Feature ID for SharePoint feature your customization belongs to" greatly saved my time. Thanks again, you do great job.

    ReplyDelete
  2. My Man! Great job, that's only solution i've found over internet that actually works with Ribbon.EditingTools.CPInsert.CustmGroup !! Best Regards :)

    ReplyDelete
  3. Hi,

    Where do I retreieve the

    const string initialTabId = "RibbonCustomization.CustomTab";

    What XML Attribute is this?

    ReplyDelete
  4. found it

    InitialTabId = [Your Tab Id]

    ReplyDelete
  5. Group Id's can be found here as well: http://msdn.microsoft.com/en-us/library/ee537543.aspx

    ReplyDelete
  6. Has anyone gotten this to work for adding a button to the Ribbon.PublishTab.Publishing or .Workflows groups? I can't seem to find a working combination of RegistrationId and RegistrationType that does the trick.

    So far I've tried:
    - List / 101
    - List / 850 (registration id for Pages Library)
    - FileType / aspx
    - ContentType / (content type id for 'page')

    has anyone ever gotten that to work?

    ReplyDelete
  7. http://www.ultraboostuncaged.us/ Ultra Boost Uncaged
    http://www.outlettoms.us/ Toms Outlet
    http://www.cheap--jordanshoes.us.com/ Jordan Shoes
    http://www.rayban-outlets.com/ Ray Ban Outlet
    http://www.oakleyoutlet-store.us/ Oakley Outlet
    http://www.longchampoutletstore.org/ Longchamp Outlet Store
    http://www.yeezy.com.co/ Yeezy
    http://www.kedsshoesforwomen.com/ Keds Shoes For Women
    http://www.nikeoutlet.org.uk/ Nike UK
    http://www.jordan4.us/ Jordan 4
    http://www.nikehuarache.us/ Nike Huarache
    http://www.adidasnmd.us.com/ Adidas NMD
    http://www.nikeoutletfactorystore.com/ Nike Factory Outlet
    http://www.mlb-jerseys.us/ MLB Jerseys
    http://www.outletrayban.us/ Ray Ban Outlet
    http://www.jordan12.us/ Jordan 12
    http://www.ray-banoutlets.us/ Ray Bans Outlet
    http://www.yeezyboost350.us.com/ Adidas Yeezy
    http://www.ray-banoutlet.site/ Ray Ban Outlet Online
    http://www.ralphlaurenoutletstoreonline.com/ Ralph Lauren Outlet Online
    http://www.uggboots-outlets.com/ UGG Boots Outlet
    http://www.underarmouroutlet.us.com/ Under Armour Outlet
    http://www.yeezyboost350.us.com/ Yeezy Boost 350
    http://www.nikeoutletsstore.com/ Nike Outlet Store
    http://www.longchampbags.us.com/ Longchamp Bags
    http://www.nikerosherun.us.com/ Roshe Run
    http://www.nikeairmax.us/ Air Max
    http://www.airmax2016.us.com/ Air Max 2016
    http://www.yeezy-shoes.us.com/ Yeezy
    http://www.nfljerseys.us/ NFL Jersey
    http://www.poloralphlaurenoutlets.us.com/ Polo Ralph Lauren Outlet
    http://www.adidas-uk.org.uk/ Adidas UK
    http://www.timberlanduk.org.uk/ Timberland UK
    http://www.ralphlaurens.org.uk/ Ralph Lauren
    http://www.yeezyboost-350.org.uk/ Yeezy Boost 350
    http://www.nikeoutlet.org.uk/ Nike Outlet
    http://www.yeezyboost-350.in.net/ Yeezy Boost 350
    http://www.rayban-sunglasses.ca/ Ray Ban Sunglasses

    ReplyDelete