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/">
- ...
- <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
- 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:
- 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;
- 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;
- 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:
- The Location attribute of CommandUIDefinition xml element should be exactly the following: Ribbon.Tabs._children;
- 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:
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:
- rotected 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;
- }
- }