How to Create a Web Part with a Contextual Tab

This post will cover how to create a Web Part that opens a contextual tab on the Server ribbon in Microsoft SharePoint Foundation 2010. You will be working with Server ribbon XML, EcmaScript (JavaScript, JScript), and C# code. This solution will be a farm solution and will be built using Visual Studio 2010 Beta 2. If you have any questions, please feel free to leave a comment.

 The following will appear in a future version of the SDK. It is preliminary documentation and subject to change.

First, you will create a new project. Click on File, New, and then Project.

1. Under Visual C#, choose Empty SharePoint Project and enter ContextualTabWebPart for the Name. Click OK.

2. In the SharePoint Customization Wizard, choose Deploy as a farm solution. Click Finish.

Now, you will implement the Web Part.

3. In the Solution Explorer, right click References and choose Add Reference.

4. On the Add Reference dialog, choose the .NET Tab. Select Microsoft.Web.CommandUI.dll. Click OK.

5. Right click on the ContextualTabWebPart project in the Solution Explorer and choose Add, New Item...

6. In the Add New Item dialog, choose Web Part. Enter ContextualTabWebPart as the name.

7.  When the Web Part has been added and ContextualTabWebPart.cs file is shown, add the following using statements.

using System.Xml;

using Microsoft.Web.CommandUI;

 

8. Now, you need to implement the IWebPartPageComponentProvider interface as follows. You will work with this later.

public class ContextualTabWebPart : WebPart, IWebPartPageComponentProvider

 

9. Next, you will create two global string variables for the ribbon XML. These two variables define the contextual tab and the group template. For a more in-depth discussion on defining a tab and group template, see How to Add a Tab to the Server Ribbon in SharePoint Foundation. In the contextualTab string, you will notice a ContextualGroup element. This element defines the following Tab element as a contextual tab. The Color attribute defines the color of the tab when it renders. The Id and ContextualGroupId are simply unique identifiers for the group. The Sequence attribute defines where the contextual tab will render. The following code implements the two global string variables.

        private string contextualTab = @"

   <ContextualGroup Color=""Magenta""

     Command=""CustomContextualTab.EnableContextualGroup""

     Id=""Ribbon.CustomContextualTabGroup""

     Title=""Custom Contextual Tab Group""

     Sequence=""502""

     ContextualGroupId=""CustomContextualTabGroup"">

          <Tab

              Id=""Ribbon.CustomTabExample""

              Title=""My Custom Tab""

              Description=""This holds my custom commands!""

              Command=""CustomContextualTab.EnableCustomTab""

              Sequence=""501"">

            <Scaling

              Id=""Ribbon.CustomTabExample.Scaling"">

              <MaxSize

  Id=""Ribbon.CustomTabExample.MaxSize""

                GroupId=""Ribbon.CustomTabExample.CustomGroupExample""

                Size=""OneLargeTwoMedium""/>

              <Scale

                Id=""Ribbon.CustomTabExample.Scaling.CustomTabScaling""

                GroupId=""Ribbon.CustomTabExample.CustomGroupExample""

                Size=""OneLargeTwoMedium"" />

            </Scaling>

            <Groups Id=""Ribbon.CustomTabExample.Groups"">

     <Group

                Id=""Ribbon.CustomTabExample.CustomGroupExample""

                Description=""This is a custom group!""

                Title=""Custom Group""

                Command=""CustomContextualTab.EnableCustomGroup""

        Sequence=""52""

                Template=""Ribbon.Templates.CustomTemplateExample"">

                <Controls

                  Id=""Ribbon.CustomTabExample.CustomGroupExample.Controls"">

                  <Button

                    Id=""Ribbon.CustomTabExample.CustomGroupExample.HelloWorld""

                    Command=""CustomContextualTab.HelloWorldCommand""

                    Sequence=""15""

                    Description=""Says hello to the World!""

                    LabelText=""Hello, World!""

                    TemplateAlias=""cust1""/>

                  <Button

                    Id=""Ribbon.CustomTabExample.CustomGroupExample.GoodbyeWorld""

                    Command=""CustomContextualTab.GoodbyeWorldCommand""

      Sequence=""17""

                    Description=""Says good-bye to the World!""

                    LabelText=""Good-bye, World!""

                    TemplateAlias=""cust2""/>

                </Controls>

              </Group>

           </Groups>

          </Tab>

   </ContextualGroup>";

        private string contextualTabTemplate = @"

          <GroupTemplate Id=""Ribbon.Templates.CustomTemplateExample"">

            <Layout

              Title=""OneLargeTwoMedium"" LayoutTitle=""OneLargeTwoMedium"">

              <Section Alignment=""Top"" Type=""OneRow"">

                <Row>

                  <ControlRef DisplayMode=""Large"" TemplateAlias=""cust1"" />

                </Row>

              </Section>

              <Section Alignment=""Top"" Type=""TwoRow"">

                <Row>

                  <ControlRef DisplayMode=""Medium"" TemplateAlias=""cust2"" />

                </Row>

                <Row>

                  <ControlRef DisplayMode=""Medium"" TemplateAlias=""cust3"" />

                </Row>

              </Section>

            </Layout>

          </GroupTemplate>";

10. Create a new string property called DelayScript. DelayScript contains EcmaScript (JavaScript, JScript) that adds and registers your custom page component. We will create the custom page component later in this topic. The _addCustomPageComponent method creates your custom page component and adds it to the page manager. Every Web Part has a page component, and you will use the Web Part's page component id when you create a custom page component object. This is necessary to associate the Web Part with the page component to enable contextually switching to your custom ribbon tab. The _registerCustomPageComponent method registers your EcmaScript file when the page loads. The following code implements DelayScript .

        public string DelayScript

        {

            get

            {

                string webPartPageComponentId = SPRibbon.GetWebPartPageComponentId(this);

                return @"

<script type=""text/javascript"">

//<![CDATA[

            function _addCustomPageComponent()

            {

                var _customPageComponent = new ContextualTabWebPart.CustomPageComponent('" + webPartPageComponentId + @"');

                SP.Ribbon.PageManager.get_instance().addPageComponent(_customPageComponent);

            }

            function _registerCustomPageComponent()

            {

                SP.SOD.registerSod(""CustomContextualTabPageComponent.js"", ""\/_layouts\/CustomContextualTabPageComponent.js"");

                SP.SOD.executeFunc(""CustomContextualTabPageComponent.js"", ""ContextualWebPart.CustomPageComponent"", _addCustomPageComponent);

            }

            SP.SOD.executeOrDelayUntilScriptLoaded(_registerCustomPageComponent, ""sp.ribbon.js"");

//]]>

</script>";

            }

        }

11. Create a new function called AddContextualTab. Inside the AddContextualTab method, you will insert code to register the contextual tab and custom templates with the ribbon. The Microsoft.Web.CommandUI.Ribbon.RegisterDataExtension method will be used to register the ribbon extensions. RegisterDataExtension tells the ribbon where to load the XML passed into it. We will use the ids of the ContextualTabs and Templates elements in CMDUI.xml. The following code implements the AddContextualTab method.

        private void AddContextualTab()

        {

            //Gets the current instance of the ribbon on the page.

            Microsoft.Web.CommandUI.Ribbon ribbon = SPRibbon.GetCurrent(this.Page);

            //Prepares an XmlDocument object used to load the ribbon extensions.

            XmlDocument ribbonExtensions = new XmlDocument();

            //Load the contextual tab XML and register the ribbon extension.

            ribbonExtensions.LoadXml(this.contextualTab);

            ribbon.RegisterDataExtension(ribbonExtensions.FirstChild, "Ribbon.ContextualTabs._children");

            //Load the custom templates and register the ribbon extension.

            ribbonExtensions.LoadXml(this.contextualTabTemplate);

            ribbon.RegisterDataExtension(ribbonExtensions.FirstChild, "Ribbon.Templates._children");

        }

 

12. Now, you need to implement the WebPartContextualInfo property of the IWebPartPageComponentProvider interface. You can implement the interface by right clicking on IWebPartPageComponentProvider and choosing Implement Interface, Implement Interface Explicitly.

 

This interface lets the ribbon know when a Web Part has been selected and which contextual group and tab to show. When you add the contextual group, you send it the id of the contextual group, the VisibilityContext, and the Command. The id maps to the Id property of the ContextualGroup element in the ribbon XML. The VisibilityContext is used to group controls in order to show or hide them. The Command parameter maps to the Command of the ContextualGroup element in the ribbon XML. You will also add the tab that was defined in the ribbon XML. You only need to pass in the Id and the VisibilityContext parameters for the tab.

Insert the following code for the WebPartContextualInfo.

        public WebPartContextualInfo WebPartContextualInfo

        {

            get

            {

                WebPartContextualInfo info = new WebPartContextualInfo();

                WebPartRibbonContextualGroup contextualGroup = new WebPartRibbonContextualGroup();

                WebPartRibbonTab ribbonTab = new WebPartRibbonTab();

                //Create the contextual group object and initialize its values.

                contextualGroup.Id = "Ribbon.CustomContextualTabGroup";

                contextualGroup.Command = "CustomContextualTab.EnableContextualGroup";

                contextualGroup.VisibilityContext = "CustomContextualTab.CustomVisibilityContext";

                //Create the tab object and initialize its values.

                ribbonTab.Id = "Ribbon.CustomTabExample";

                ribbonTab.VisibilityContext = "CustomContextualTab.CustomVisibilityContext";

                //Add the contextual group and tab to the WebPartContextualInfo.

                info.ContextualGroups.Add(contextualGroup);

                info.Tabs.Add(ribbonTab);

                info.PageComponentId = SPRibbon.GetWebPartPageComponentId(this);

                return info;

            }

        }

13. Next, you will implement the OnPreRender method. This allows us to add elements to the ribbon before it is rendered on the page. Inside OnPreRender you will call the AddContextualTab method and register the DelayScript with the ClientScriptManager. The following code implements OnPreRender.

        protected override void OnPreRender(EventArgs e)

        {

            base.OnPreRender(e);

            this.AddContextualTab();

            ClientScriptManager clientScript = this.Page.ClientScript;

            clientScript.RegisterClientScriptBlock(this.GetType(), "ContextualTabWebPart", this.DelayScript);

        }

 

The Web Part is complete. Next, you will create the page component. A page component is an EcmaScript (JavaScript, JScript) object used to interact with the Server ribbon. It enables commands on the ribbon and responds to the commands you define in the ribbon XML. The page component has required functions in order for it to operate properly. The following table lists the required functions and their purpose.

Function

Purpose

init

Initializes the page component.

getFocusedCommands

Returns a list of the focused commands. Your page component is called for the commands only if it has the focus

getGlobalCommands

Returns a list of the global commands. Your page component is called for commands regardless of focus.

isFocusable

Specifies if the page component can receive focus.

canHandleCommand

Defines if the page component can handle a command sent to it.

handleCommand

Handles the commands sent to the page component.

getId

Returns the id of the page component. This is used to associate a control with a page component.

 

There are also two optional functions. These functions will not be defined in this example.

Function

Purpose

yieldFocus

Specifies the code that is run when the page component loses focus.

receiveFocus

Specifies the code that is run when the page component receives focus.

 

In order for the page component to operate properly, you will have to deploy the file using a Module.

14. In the Solution Explorer, right click on the ContextualTabWebPart project and select Add, New Item.

15. In the Add New Item dialog, choose the Module template and type CustomContextualTabPageComponent as the Name. Click Add.

16. You will not need the files that are added by default. Select Elements.xml and Sample.txt in the Solution Explorer and delete them.

17. Now, you need to add the EcmaScript (JavaScript, JScript) file. Right click on CustomContextualTabPageComponent and select Add, New Item.

18. Under Visual C#, choose Web in the Installed Templates list. Select the Jscript File type and enter CustomContextualTabPageComponent as the name.

19. You will need to set the deployment location to make sure the file goes into the _layouts directory. To do that, select CustomContextualTabPageComponent.js in the Solution Explorer. In the Properties window, set the Deployment Type to Root File. Open the Deployment Location property and set the Path to Template\Layouts.

The following code will go into the CustomContextualTabPageComponent.js file to implement your custom page component.

Type.registerNamespace('ContextualTabWebPart');

var _webPartPageComponentId;

ContextualTabWebPart.CustomPageComponent = function ContextualTabWebPart_CustomPageComponent(webPartPcId) {

    this._webPartPageComponentId = webPartPcId;

    ContextualTabWebPart.CustomPageComponent.initializeBase(this);

}

ContextualTabWebPart.CustomPageComponent.prototype = {

    init: function ContextualTabWebPart_CustomPageComponent$init() { },

    getFocusedCommands: function ContextualTabWebPart_CustomPageComponent$getFocusedCommands() {

        return ['CustomContextualTab.EnableCustomTab', 'CustomContextualTab.EnableCustomGroup', 'CustomContextualTab.HelloWorldCommand', 'CustomContextualTab.GoodbyeWorldCommand'];

    },

    getGlobalCommands: function ContextualTabWebPart_CustomPageComponent$getGlobalCommands() {

        return [];

    },

    isFocusable: function ContextualTabWebPart_CustomPageComponent$isFocusable() {

        return true;

    },

   

    canHandleCommand: function ContextualTabWebPart_CustomPageComponent$canHandleCommand(commandId) {

        //Contextual Tab commands

        if ((commandId === 'CustomContextualTab.EnableCustomTab') || (commandId === 'CustomContextualTab.EnableCustomGroup') || (commandId === 'CustomContextualTab.HelloWorldCommand') || (commandId === 'CustomContextualTab.GoodbyeWorldCommand')) {

            return true;

        }

    },

    handleCommand: function ContextualTabWebPart_CustomPageComponent$handleCommand(commandId, properties, sequence) {

        if (commandId === 'CustomContextualTab.HelloWorldCommand') {

            alert('Hello, world!');

        }

        if (commandId === 'CustomContextualTab.GoodbyeWorldCommand') {

            alert('Good-bye, world!');

        }

    },

    getId: function ContextualTabWebPart_CustomPageComponent$getId() {

        return this._webPartPageComponentId;

    }

}

ContextualTabWebPart.CustomPageComponent.registerClass('ContextualTabWebPart.CustomPageComponent', CUI.Page.PageComponent);

SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("CustomContextualTabPageComponent.js");

 

Notice that getFocusedCommands returns the Command properties that you defined in the ribbon XML above. In canHandleCommand you return true to signify that your page component can respond to the specified commands. When creating this object, you use the webPartPcId parameter to set the custom page component id. This is set to the same value as the Web Part’s page component id to associate the Web Part and page component through the getId method.

20. To test the code, press F5 to deploy the solution.

21. Open your site and put the page into Edit mode.

22. In the Insert tab, click the Web Part button.

23. In the Web Part Adder, select the Custom category.

24. In the list of Web Parts, select ContextualTabWebPart. Click Add.

25. Once the Web Part is added to the page, click the ContextualTabWebPart.

26. Notice the Custom Contextual Tab Group tab that shows up on selection.