Wednesday, March 20, 2013

Customizing and Extending the SharePoint 2010 Server Ribbon

Introduction to the SharePoint 2010 Server Ribbon

With the release of the 2007 Microsoft Office system, Microsoft introduced a new user interface structure, known as the ribbon, that replaced the previous application drop-down menus and toolbars. The ribbon came about after much research suggested that certain applications, such as Microsoft Word, contained so many commands that users had trouble finding what they needed.
The premise behind the ribbon is that it provides a more results-driven interface. Users focus on what they are doing, and commands are presented only for those things they can do at a specific time. For example, there is no reason to provide commands to the user to interact with tables or images in a document when they are clearly typing text and do not have an image or table selected. However, by using the Insert tab, they can easily add a table or picture. Only when they have selected the table or picture do new command structures appear. When the table or picture loses focus, these commands disappear.
In the 2007 Microsoft Office system, the ribbon was implemented in Microsoft Word, Microsoft Excel, and Microsoft PowerPoint. Microsoft expanded on this and has added the ribbon to the all the Microsoft Office 2010 applications, including Microsoft OneNote 2010, Microsoft Access 2010, and Microsoft InfoPath 2010.
Like the Microsoft Office clients, SharePoint users were experiencing similar challenges in finding controls to complete their work. Commands existed in multiple places across the page, from the Site Actions menu to managing Web Parts, or to the Edit Control Block (ECB) menus in lists. Figure 1 shows all the menus that are available to users in a Windows SharePoint Services 3.0 site.
Figure 1. Menus and commands in Windows SharePoint Services 3.0

Windows SharePoint Services site menus
In Microsoft SharePoint 2010, Microsoft added the Server ribbon to SharePoint to address the same challenges users had with the many commands in the Microsoft Office clients. All commands and menu items have been pushed from the main workspace in SharePoint up into the ribbon, which remains pinned to the top of the browser window. Users of the 2007 Microsoft Office system or other applications that have implemented the ribbon will find the SharePoint ribbon very easy to adjust to because it is very similar to the Office client ribbons. It looks, works, and performs like the Office ribbon, and has the same controls as the Office ribbon. The only differences between the Office ribbon and the SharePoint Server ribbon are concerned with the technologies; for example, it is not easy to show different font renderings in the web (thin client) experience as it is in the desktop (thick client) experience.
The ribbon in SharePoint 2010 is built on a similar architecture to the Office client ribbon. Microsoft uses this architecture to implement the default ribbon in SharePoint 2010. This architecture also enables third-party developers to customize and extend the existing ribbon components that are included in SharePoint, and to create command structures.
This article explains the components of the SharePoint Server ribbon so that you can understand how the ribbon is constructed. Then, it explains and shows how developers can customize and extend the ribbon. The SharePoint Foundation 2010 General Reference has a section devoted to explaining the ribbon, and contains various customization walkthroughs. When customizing the ribbon, I recommend that you use this article in conjunction with the SharePoint Foundation 2010 General Reference, specifically the section Server Ribbon in SharePoint Foundation.

SharePoint 2010 Server Ribbon Architecture

The default ribbon is built by SharePoint and is based on a single file that is part of the main installation. This file is part of the global site definition that is found in the path{SharePoint Root}\TEMPLATE\GLOBAL\XML\CMDUI.XML. This file contains the definitions for the ribbon components in SharePoint Foundation 2010, such as theBrowsePageListLibrary, and Document tabs.
Although the CMDUI.xml file contains all the core Server ribbon components, this is not how additional customizations to the ribbon are implemented. SharePoint Features are used to implement additional changes to the ribbon. For example, Microsoft SharePoint Server 2010 includes many things that require ribbon modifications such as those related to Enterprise Content Management, Forms Services, and business intelligence. These changes are all implemented by using SharePoint Features. SharePoint developers can also customize the ribbon by using Features as described in Creating Custom SharePoint 2010 Server Ribbon Components, later in this article.
SharePoint 2010 has extended the Feature schema, specifically the <CustomAction /> element, to be the vehicle for all ribbon customizations. This is done by setting theLocation attribute to CommandUI.Ribbon, and adding a <CommandUIExtension /> child element. The SharePoint 2010 SDK provides an overview of the Server Ribbon XML.
The following sections address the two core pieces of the ribbon: the components that make up the visual experience and the code that runs when one of the controls in the ribbon is clicked.

SharePoint 2010 Server Ribbon Components

The SharePoint 2010 Server ribbon has various components, as shown in Figure 2.

Figure 2. SharePoint 2010 Server ribbon components

SharePoint 2010 server ribbon components
The callout numbers in the figure point to the following specific components:
  1. Tab
  2. Group
  3. Control
  4. Contextual tab group
The next few sections briefly explain these components and their uses.

Tabs on the SharePoint 2010 Server Ribbon

Tabs are the root of the Server ribbon. They contain one or more groups, and contain similar functions. For example, in Figure 2, the Page tab that is currently selected contains functions that pertain to working with the current page.

Contextual Tab Groups on the SharePoint 2010 Server Ribbon

Contextual tab groups are used to provide functions that are not global to the current context, such as the page. They appear only when certain circumstances have been met and contain one or more tabs.
For example, the ribbon in Figure 2 shows the Library Tools contextual tab group, which appears only when inside a document library or, as in this case, when the List View Web Part on the current page that is associated with a document library is selected.
Contextual tab groups hide functionality and menu choices from the user when they are not available, and appear when applicable. Other examples of contextual tab groups include the Editing Tools contextual tab group that appears when editing a wiki page, or the Picture Tools contextual tab group that appears when a picture is selected in edit mode.

Groups on the SharePoint 2010 Server Ribbon

Every tab in the ribbon contains a series of one or more groups. Groups are used to associate controls with similar functionality. Each group is associated with a template that defines the layout of the group and how the group should appear based on the scale of the ribbon. The scale of the ribbon refers to situations where there are too many controls to show in the ribbon, for example, when the browser is not in a full-screen maximized state and is in a windowed state.

Group Templates on the SharePoint 2010 Server Ribbon

Group templates are used to define the different layout options for the controls within a group. Microsoft includes 29 group templates in the CMDUI.xml file (to locate them, search for the element <RibbonTemplates /> at the end of this file).

Controls on the SharePoint 2010 Server Ribbon

The ribbon would not be complete if users did not have anything to select or click. Controls are the items that live inside the ribbon that users can interact with. Controls reside within groups. These include things such as buttons, toggle buttons, check boxes, text boxes and many other controls. For a complete list of all the available controls, see Architecture of the Server Ribbon.
Each control definition contains a Command attribute that tells the ribbon infrastructure what to do when it is clicked or selected.

Server Ribbon Commands in SharePoint 2010

The Server ribbon handles click or selection actions by the user with commands. Those who are familiar with how the commanding infrastructure works in Windows Presentation Foundation or Microsoft Silverlight 4 will find near parity with the Server ribbon commanding infrastructure. Each command is named. This name is referenced in a control. At the core, commands contain two very important details:
  • Whether the current command is available  For example, the Delete command is available only in a document library or if documents are selected.
  • What code should be run  For example, the Delete command may use the SharePoint 2010 client-side object model to delete the item from the list, display a notification that the document was deleted, and refresh the List View Web Part on the page.
The topic Architecture of the Server Ribbon contains additional details about exactly how the commanding infrastructure works.
Commands in the Server ribbon are written by using ECMAScript (JavaScript, JScript). There are two ways that you can implement commands:
  • Through command UI handlers
  • Through page components
The two options are explained in the following sections, and I discuss some advantages and disadvantages of each option. In general, simple and relatively small commands are suited to the command UI handler option. However, commands that get quite complex and require a considerable amount of JavaScript to implement may be better suited to page components. The example ribbon customization used in the document library sample later in this article shows how to use each technique to perform exactly the same operation.

Implementing Server Ribbon Commands Using Command UI Handlers

Command UI handlers are implemented with a mix of declarative markup and JavaScript. They are defined in the same Feature element manifest in which ribbon customizations are defined (by using the <CommandUIExtension /> element) with a <CommandUIHandler /> element. This element contains the following three attributes:
  • Command  The name of the command as it will be referenced from a control.
  • CommandAction  The JavaScript that is executed when the command is fired.
  • EnabledScript  The JavaScript that is called by the Server ribbon command infrastructure to determine whether the command is available. This script should return a Boolean value, TRUE if the command is available, or FALSE if it is not available. If the command is not available, the ribbon infrastructure applies a gray mask to the command in the ribbon and does not call the command when the user selects it.
Advantages of Using Command UI Handlers
Command UI handlers are generally easier to write and manage for most developers. Because they are defined declaratively, the ribbon framework handles adding the script to any page where the command is needed by a referencing control.
Disadvantages of Using Command UI Handlers
One of the disadvantages of command UI handlers is that they can become hard to manage, troubleshoot, and debug when they contain a significant amount of custom JavaScript. Also, because they are added to every page as inline script blocks, they cannot be cached by the browser and must be downloaded each time, adding to the overall page weight.

Implementing Server Ribbon Commands Using Page Components

An alternative to using command UI handlers is to use a page component. A page component is an JavaScript object that is defined in an external script library (.js) file. The object implements a few properties and methods that tell the Server ribbon command infrastructure how to initialize it, what commands it can handle, and whether a specific command is available, and can also respond when the page component receives focus or loses focus.
This script file must be added to the same page where the ribbon customizations appear. This can be done in various ways. One way would be to use the new <CustomAction ScriptSrc="" /> capability in SharePoint 2010 to add the library to all pages in a site, site collection, web application, or farm, depending on the Feature's scope. Another approach is to add the script from managed code within a custom application or site page (.aspx), custom user control (.ascx), or custom server control. The following code example would add the page component file to the page from within a Web Part.
private void LoadAndActivateRibbonContextualTab() {
  SPRibbon ribbon = SPRibbon.GetCurrent(this.Page);
  // Ensure ribbon exists.
  if (ribbon != null) {
    // Load dependencies if not already on the page.
    ScriptLink.RegisterScriptAfterUI(this.Page, "SP.Ribbon.js", false, true);

    // Load and activate contextual tab.
    ribbon.MakeTabAvailable("Ribbon.PropertyChangerTab");
    ribbon.MakeContextualGroupInitiallyVisible("Ribbon.WebPartContextualTabGroup", string.Empty);
  }
}

Advantages of Using Page Components
Because all the JavaScript lives in an external script library, it is much easier to manage, troubleshoot, and debug a page component instead of a command UI handler (the Microsoft Visual Studio 2010 script debugger can set breakpoints and attach to the library). In addition, because it is an external library, browsers can cache the library without having to request it each time it is referenced on the page.
Page components also enable greater control over commands because they can enable or disable the page component from receiving or losing focus and handle events in each of these cases.
In addition, because they are external libraries, one page component can handle commands for multiple controls and so can be reused across various ribbon customizations.
Disadvantages of Using Page Components
One disadvantage of using page components, compared to using command UI handlers, is that page components require a considerable amount of script. This is primarily because developers are building, registering, and initializing a script object on the page. In addition, developers who are not familiar with object-oriented JavaScript techniques can find this a bit challenging.
Another disadvantage of using page components is that they must be added to the page somehow, as this is not handled by the ribbon command infrastructure.

Customizing the SharePoint 2010 Server Ribbon

Developers are presented with two options when they want to customize the SharePoint Server ribbon. Customizations can either be applied declaratively or programmatically. The declarative approach, as described previously in this article, is done by using Features; specifically the <CustomAction /> element with the <CommandUIExtensions />child element.
The programmatic approach involves adding the declarative constructs, as strings, to the Server ribbon objects. The remainder of this article focuses on the declarative approach because these techniques can be applied to the programmatic approach also. The SharePoint 2010 SDK contains a walkthrough about customizing the ribbon programmatically: Walkthrough: Creating a Custom Web Part with a Contextual Tab.

Customizing the Built-in SharePoint 2010 Server Ribbon Components

Developers can customize the ribbon in three ways:
  • Add components to the ribbon (tabs, contextual tab groups, groups, and controls).
  • Modify existing components in the ribbon.
  • Remove existing components from the ribbon.
All three options can be performed declaratively. Server Ribbon XML walks through the different elements. And Declarative Customization of the Server Ribbon walks through how to add three common components to the ribbon.
Modifying and removing components such as tabs, groups, and controls are done very much the same way with the same schema elements. You modify an element by duplicating its ID and simply replacing its contents, very similar to the way that content placeholders work in Microsoft ASP.NET 2.0 master pages. Removing is the same as modifying, except that the container is left empty. For more information, see Declarative Customization of the Server Ribbon.

Creating Custom SharePoint 2010 Server Ribbon Components

The following two sections walk through how to customize the SharePoint 2010 Server ribbon. Both walkthroughs use various techniques, and each component is explained in detail. For the sample code for both walkthroughs, see MSDN Sample - Customizing and Extending the SharePoint 2010 Server Ribbon. This sample code requires only a SharePoint Foundation 2010 site collection.
The first sample, WebPartRibbonContextualTab, shown in Figure 3, demonstrates how to create a custom Web Part that uses the following ribbon customizations:
  • Contextual tab group
  • Custom tab
  • Custom group
  • Command UI handlers
  • Activating the contextual tab group only when the Web Part is on the page
  • Triggering and handling a server-side postback when a button is clicked on the ribbon.


Figure 3. Web Part with contextual tab group

Web Part with contextual tab group
The second sample, ApplyDocumentPrefixRibbon, shown in Figure 4, demonstrates how to implement the following customizations and techniques:
  • A custom group in an existing ribbon tab.
  • A custom group template with different layout options.
  • Two custom commands that perform identical actions, except that one is implemented with a command UI handler and the other implements a custom page component:
    • The commands are disabled unless one or more documents in the library are selected.
    • When clicked, the commands open a dialog box, pass the selected documents, and do some work based on user input.
    • When the dialog box's work is complete, the dialog box closes, and the command displays a notification message and refreshes the List View Web Part instead of the whole page.
  • A custom server control that conditionally loads the page component.


Figure 4. Custom group with page component

Custom group with page component
note Note:
Some markup from the sample code has been omitted for readability. For the complete code reference, see MSDN Sample - Customizing and Extending the SharePoint 2010 Server Ribbon.

How To: Create a Web Part–Enabled Contextual Tab and Leverage to Postbacks

In this sample, when the Web Part is added to the page the contextual tab appears as shown earlier in Figure 3. This tab contains two groups that provide a few buttons. The buttons in the first group do not do anything but do show how to use one of the default templates. However, the Write to Web Part via PostBack button issues a postback. The Web Part contains code that checks whether the button issued the postback, and if so, adds some text to the Web Part's contents.

Step 1: Create the Web Part

The first step is to create the Web Part. Using the new SharePoint development tools in Microsoft Visual Studio 2010, create a SharePoint project and add a Web Part SharePoint project item to the project. The CreateChildControls method does two things: writes some text to the Web Part, and calls a method to handle the case when a specific postback event is fired, as shown in the following code.
public class RibbonizedWebPart : WebPart {
  private string POSTBACK_EVENT = "RibbonizedWebPartPostback";

  protected override void CreateChildControls() {
    this.Controls.Add(
      new LiteralControl(
        "<em>Ribbonized Web Part contents go here</em>"
      )
    );

    // Handle postback from ribbon. 
    HandleRibbonPostback();
  }
}

Next, create the method that handles the postback event. If it is a specific postback event, it writes some additional text to the Web Part's contents, as shown in the following code.
private void HandleRibbonPostback() {
  if (this.Page.Request["__EVENTTARGET"] == POSTBACK_EVENT) {
    this.Controls.Add(
      new LiteralControl(
        "<p>Responding to postback event from ribbon.</p>"
      )
    );
  }
}

The last step is to implement the code that will add the custom contextual tab to the page. This is done from the OnPreRender phase of the Web Part's life cycle. It must get a reference to the Server ribbon and ensures the script dependencies are already loaded on the page. Finally, to show the contextual tab, it then makes the tab with an ID ofRibbon.PropertyChangerTab available, and tells the ribbon to make the contextual tab with an ID of Ribbon.WebPartContextualTabGroup available when the page loads, as shown in the following code.
protected override void OnPreRender(EventArgs e) {
  LoadAndActivateRibbonContextualTab();
  base.OnPreRender(e);
}

private void LoadAndActivateRibbonContextualTab() {
  SPRibbon ribbon = SPRibbon.GetCurrent(this.Page);
  // Ensure ribbon exists.
  if (ribbon != null) {
    // Load dependencies if not already on the page.
    ScriptLink.RegisterScriptAfterUI(this.Page, 
      "SP.Ribbon.js", false, true);

    // Load and activate contextual tab.
    ribbon.MakeTabAvailable("Ribbon.PropertyChangerTab");
    ribbon.MakeContextualGroupInitiallyVisible(
      "Ribbon.WebPartContextualTabGroup", string.Empty);
  }
}

Step 2: Create Server Ribbon Component Customizations

With the Web Part created, the next step is to create the Server ribbon component customizations. To do this, you create a contextual tab group, a tab with two groups, and a few controls.
The SharePoint development tools in Microsoft Visual Studio 2010 do not contain a SharePoint project item template for customizing the ribbon. However, the generic SharePoint project item Empty Element will work to contain the ribbon customizations, so add a new one to the project.

Step 2.1: Add the Core Ribbon Markup to the Element

Add the following markup to the element.xml file in the new Element SharePoint project item for the project.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="WebPartContextualTabs" Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions />
      <CommandUIHandlers />
    </CommandUIExtension>
  </CustomAction>
</Elements>

This will tell SharePoint the following:
  • The element manifest contains ribbon customizations that apply to the ribbon everywhere (<CustomAction Location="CommandUI.Ribbon" />). There are five options for the Location attribute. The others enable developers to specify that the customizations should appear when the List View Web Part is present or on the display, new, or edit forms for an item. In addition, RegistrationType and RegistrationId enable developers to more granularly target where the customizations appear. For example, they could be targeted to a specific content type. All options are listed in Server Ribbon XML.
  • The basic structure for a ribbon customization is also included.

Step 2.2: Add a New Contextual Tab Group

Next, add the following markup that will create the contextual tab group.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="WebPartContextualTabs" Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition 
                Location="Ribbon.ContextualTabs._children">
          <ContextualGroup Id="Ribbon.WebPartContextualTabGroup"
                ContextualGroupId="WebPartContextualTab"
                Title="Ribbonized Web Part Tools"
                Sequence="150"
                Color="Green"
                Command="WebPartContextualTab.OnEnableContextualTab">
          </ContextualGroup>
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers />
    </CommandUIExtension>
  </CustomAction>
</Elements>

The <CommandUIDefinition> Location attribute tells the ribbon to add the following contents, which are one or more <ContextualGroup /> elements, to the contextual tabs in the ribbon.
The <ContextualGroup /> element defines the new group. It has an Id attribute that matches the name of the contextual group that the Web Part's code told the ribbon to make visible initially when the page loaded.
The Sequence attribute tells SharePoint the order where this contextual group should exist when other contextual groups are present. The SharePoint contextual groups are given sequences that increment by 100, starting with 100, which is the Editing Tools contextual group. Therefore, our contextual group may show up first or second if theEditing Tools group is present. For information about how to find the names and sequences for other contextual groups, see the Custom SharePoint 2010 Server Ribbon Development Tips and Tricks section, later in this article.
The Command attribute associates this group with a command name. In some cases, it may make sense to have script run when this tab group is selected. However, in this case the command (implemented later) is used to tell the ribbon when to activate the contextual group. If this were not implemented, when a user clicked on anything it would trigger the ribbon to hide the custom group.

Step 2.3: Add a Tab to the Contextual Tab Group

With the contextual tab group created, add the following markup to add a new tab and define the maximum size layout group template.
<CommandUIDefinitions>
  <CommandUIDefinition Location="Ribbon.ContextualTabs._children">
    <ContextualGroup Id="Ribbon.WebPartContextualTabGroup" ... >
      <Tab Id="Ribbon.PropertyChangerTab" 
           Title="Tools" Sequence="501">
        <Scaling Id="Ribbon.PropertyChangerTab.Scaling">
          <MaxSize Id="Ribbon.PropertyChangerTab.MaxSize"
             GroupId="Ribbon.PropertyChangerTab.PropertyGroup"
             Size="LargeLarge" />
          <MaxSize Id="Ribbon.PropertyChangerTab.MaxSize" ... />
        </Scaling>
      </Tab>
    </ContextualGroup>
  </CommandUIDefinition>
</CommandUIDefinitions>

There are two things to notice in this snippet around the <MaxSize /> element. It associates the group defined later (via the GroupId attribute) with the layout optionLargeLarge (via the Size attribute) that is defined in the template.

Step 2.4: Add Groups to the Tab

Now add the groups to the new tab by adding the following markup.
<CommandUIDefinitions>
  <CommandUIDefinition Location="Ribbon.ContextualTabs._children">
    <ContextualGroup Id="Ribbon.WebPartContextualTabGroup" ... >
      <Tab Id="Ribbon.PropertyChangerTab" ... >
        <Scaling Id="Ribbon.PropertyChangerTab.Scaling" ... >
        </Scaling>
        <Groups Id="Ribbon.PropertyChangerTab.Groups">
          <Group Id="Ribbon.PropertyChangerTab.PropertyGroup" ... >
            ...
          </Group>
          <Group Id="Ribbon.PropertyChangerTab.PostBackGroup"
                 Title="PostBack" Sequence="25"
                 Template="Ribbon.Templates.Flexible2">
          </Group>
        </Groups>
      </Tab>
    </ContextualGroup>
  </CommandUIDefinition>
</CommandUIDefinitions>

Although there are two groups in this sample, only the second one is shown in this code listing. Notice the groups have Id attributes that match the <MaxSize GroupId="" />elements that were previously added.
Also notice that the groups are using a template named Ribbon.Templates.Flexible2. This template is included in the built-in CMDUI.xml ribbon declaration. When defining custom groups in ribbon customization Features, Microsoft recommends that developers create their own group template instead of using one of the provided group templates.The reason for this is that SharePoint does not load the entire ribbon for every page request; only the parts of the ribbon that are needed for the current context are loaded. This includes the group templates. Therefore, if developers rely on the built-in group templates, there is a chance the template will not be loaded for the current page and their ribbon customizations will not appear.
In the case of this sample customization, because this is part of a Web Part and a Web Part must be on a Web Parts page, an assumption is being made that this template will be loaded because it is part of the Page tab, which is on every Web Parts page.
For information about how to find the names of other templates, see Custom SharePoint 2010 Server Ribbon Development Tips and Tricks later in this article.

Step 2.5: Add Controls to the Group

The last step in defining the visual part of the ribbon customization is to add controls to the groups. Add the following markup to the second group (refer to MSDN Sample - Customizing and Extending the SharePoint 2010 Server Ribbon for adding buttons to the first group).
<CommandUIDefinitions>
  <CommandUIDefinition Location="Ribbon.ContextualTabs._children">
    <ContextualGroup Id="Ribbon.WebPartContextualTabGroup" ... >
      <Tab Id="Ribbon.PropertyChangerTab" ... >
        <Scaling Id="Ribbon.PropertyChangerTab.Scaling" ... >
        </Scaling>
        <Groups Id="Ribbon.PropertyChangerTab.Groups">
          <Group Id="Ribbon.PropertyChangerTab.PropertyGroup" ... >
            ...
          </Group>
          <Group Id="Ribbon.PropertyChangerTab.PostBackGroup" ... >
            <Controls Id="Ribbon.PropertyChangerTab.PropertyGroup.Controls">
              <Button Id="Ribbon.PropertyChangerTab.PropertyGroup.GeneralDialogButton"
                      LabelText="Write to Web Part"
                      Command="WebPartContextualTabs.OnPostback"
                      TemplateAlias="o1"
                      Sequence="15"
                      Image16by16="/_layouts/Images/WebPartRibbonContextualTab/16x16Placeholder.png"
                      Image32by32="/_layouts/Images/WebPartRibbonContextualTab/32x32Placeholder.png" />
            </Controls>
          </Group>
        </Groups>
      </Tab>
    </ContextualGroup>
  </CommandUIDefinition>
</CommandUIDefinitions>

This markup will add a new button control to the group with a label of Write to Web Part. When this button is clicked, it will trigger the Command="". The TemplateAliasattribute tells the Server ribbon in what position in the defined group template to place the button. Finally, the two image attributes are used by the layouts to show the ribbon icons in different states. These images can point to any image on the server. In this case, they are pointing to images that were added to the project.

Step 3: Create Server Ribbon Commands

The last step is to define the two commands that were referenced in the ribbon components. Add the following markup to the element manifest.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="WebPartContextualTabs" Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions>
        ...
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="WebPartContextualTab.OnEnableContextualTab"
          CommandAction=""
          EnabledScript="return true;" />
        <CommandUIHandler Command="WebPartContextualTabs.OnPostback"
          CommandAction="javascript:__doPostBack('RibbonizedWebPartPostback','');" />
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>
</Elements>

The first <CommandUIHandler /> has a command that is associated with the contextual tab group. As previously discussed, this command does not do anything except to tell the Server ribbon when it should be active. To keep it from disappearing from the ribbon, its EnabledScript attribute will always return TRUE. Therefore, if the contextual tab group is on the page, which it is when the Web Part is on the page because the Web Part handles its activation, it will never disappear.
The second <CommandUIHandler /> is associated with the button control. When it is clicked it fires a postback with an event named RibbonizedWebPartPostBack. Recall previously the code from the Web Part is listening for that event name and adds text to the Web Part when it sees it.

Step 4: Deploy and Test

After saving all changes, deploy the custom Web Part by pressing F5 in Visual Studio 2010 or by clicking Start Debugging on the Debug menu.
When the initial page loads, notice that the contextual tab is not present, as shown in Figure 5.


Figure 5. Home page of debugging site without contextual tab group

Home page of debugging site without contextual tab
Now, put the page into edit mode by selecting the Page tab and then clicking Edit. Insert the Web Part on the page in the default location. When the page reloads, notice the contextual tab and the Web Part are visible, as shown in Figure 6.


Figure 6. Contextual tab and Web Part are visible

Contextual tab and Web Part are visible
Test the postback by selecting the Tools tab in the custom contextual tab group, and then clicking the appropriate button. The page should refresh and have additional text in the Web Part, as shown in Figure 7.


Figure 7. Web Part responding to postback from ribbon

Web Part responding to postback from ribbon
Also notice that the contextual tab group is appearing as the second contextual tab group on the page. That is because the page is still in edit mode and the sequence was set to 150, which is greater than the Editing Tools sequence. After the page is taken out of edit mode, the custom contextual group should appear in the first position.

Walkthrough: Add Buttons to the Document Tab and Conditionally Enable Them

The sample for this walkthrough shows how to add a new group with buttons to an existing ribbon. When the project is deployed, it registers a new group in the Documentstab, which is part of the Library Tools contextual tab group. This contextual tab group will appear only when the user is interacting with documents or in a document library. Figure 8 shows the home page of a team site without the ribbon, but when the Shared Documents Library is selected, as shown in Figure 9, the contextual tab group appears with the customizations.


Figure 8. Team site home page without document library selected

Team site page without document library selected


Figure 9. Team site home page with document library selected

Team site page with document library selected
Initially two of the three buttons are not enabled. It is not until one or more documents are selected that the commands associated with the buttons are enabled, as shown in Figure 10.


Figure 10. Ribbon buttons enabled when a document is selected

Ribbon buttons enabled when a document is selected
The two latter buttons, Apply Prefix w/ CommandUI Handler and Apply Prefix w/ Page Component, do the exact same thing when clicked. However, as their names indicate, one uses the command UI handlers and the other uses a custom page component. When clicked, they collect a list of all the selected documents on the page and pass them to a new dialog box, as shown in Figure 11. This dialog box enables the user to add a prefix to the name of all selected documents.


Figure 11. Custom dialog box fired from ribbon customizations

Custom dialog box fired from ribbon customizations
When the Set Prefix button is clicked, the dialog box updates the names of all documents and then closes. Depending on whether the dialog box was closed by clicking theSet Prefix button or by clicking Cancel, the command issues a notification message and then refreshes the List View Web Part on the page, updating the list's contents.

Step 1: Create Server Ribbon Component Customizations

The first step is to create a new SharePoint empty project by using the SharePoint development tools in Microsoft Visual Studio 2010. When the project is created, add a newEmpty Element project item to the project that will contain the ribbon customizations.

Step 1.1: Add the Core Ribbon Markup to the Element

Within the element manifest, add the following markup.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="Ribbon.Documents.ApplyDocumentPrefix" Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.Documents.Groups._children">
          <Group Id="Ribbon.Documents.ApplyDocumentPrefix"
                 Title="Document Naming Tools"
                 Description="Document Naming Tools Description"
                 Sequence="25"
                 Template="Ribbon.Templates.MsdnTemplate">
          </Group>
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers />
    </CommandUIExtension>
  </CustomAction>
</Elements>

This will add a new group to the Document tab's groups collection named Document Naming Tools, as indicated by <CommandUIDefinition Location="Ribbon.Documents.Groups._children">. The group has a Sequence of 25. The groups in the built-in SharePoint 2010 Server ribbon are numbered in increments of 10, starting at 10. This means that the custom group defined here will show up in the third position.
In addition, the group will not use one of the existing group templates, but instead will use a custom group template.

Step 1.2: Add Custom Group Template

Add the following markup to add a custom group to the ribbon.
<CommandUIExtension>
  <CommandUIDefinitions>
    <CommandUIDefinition Location="Ribbon.Documents.Groups._children">
      <Group Id="Ribbon.Documents.ApplyDocumentPrefix" ... > 
        ...
      </Group>
    </CommandUIDefinition>
    <CommandUIDefinition Location="Ribbon.Templates._children">
      <GroupTemplate Id="Ribbon.Templates.MsdnTemplate">
        <Layout Title="MsdnHorizontal">
          <Section Type="OneRow">
            <Row>
              <ControlRef DisplayMode="Large" TemplateAlias="o1" />
              <ControlRef DisplayMode="Large" TemplateAlias="o2" />
              <ControlRef DisplayMode="Large" TemplateAlias="o3" />
            </Row>
          </Section>
        </Layout>
        <Layout Title="MsdnVertical">
          <Section Type="ThreeRow">
            <Row><ControlRef DisplayMode="Medium" TemplateAlias="o1" /></Row>
            <Row><ControlRef DisplayMode="Medium" TemplateAlias="o2" /></Row>
            <Row><ControlRef DisplayMode="Medium" TemplateAlias="o3" /></Row>
          </Section>
        </Layout>
       <Layout Title="MsdnVerticalTextOnly">
          <Section Type="ThreeRow">
            <Row><ControlRef DisplayMode="Menu" TemplateAlias="o1" /></Row>
            <Row><ControlRef DisplayMode="Menu" TemplateAlias="o2" /></Row>
            <Row><ControlRef DisplayMode="Menu" TemplateAlias="o3" /></Row>
          </Section>
        </Layout>
      </GroupTemplate>
    </CommandUIDefinition>
  <CommandUIDefinitions>
  <CommandUIHandlers />
</CommandUIExtension>

This template, Ribbon.Templates.MsdnTemplate, contains three different layouts. Each <Layout /> has a Title attribute, which is referenced in the <MaxSize /> element or the <Scale /> element. This tells the ribbon which template to use for the layout. Each <Layout /> element has a <Section /> that defines how the group will be rendered by using the Type attribute. This can be one of four options to render the group, using one, two, or three rows, or by using a divider. For more information, see Section Element.
The <Section /> contains one or more <Row /> elements that define each row in the layout. These <Row /> elements contain <ControlRef /> elements that serve as placeholders for controls. The DisplayMode attribute tells the ribbon how to render the control, by using just the text label, the large icon, the small icon, or one of the other choices that are defined in the schema of the ControlRef element. The TemplateAlias attribute is used to call out a specific control placement. When adding controls to the group, each control's TemplateAlias attribute will match one of these TemplateAlias attributes to specify exactly where to place the control.
Now add the following markup to tell the ribbon how to render the group by using one of the layouts in the defined template.
<CommandUIExtension>
  <CommandUIDefinitions>
    <CommandUIDefinition Location="Ribbon.Documents.Groups._children">
      <Group Id="Ribbon.Documents.ApplyDocumentPrefix" ... >
        ...
      </Group>
    </CommandUIDefinition>
    <CommandUIDefinition Location="Ribbon.Documents.Scaling._children">
      <MaxSize Id="Ribbon.Documents.Scaling.ApplyDocumentPrefix.MaxSize"
               GroupId="Ribbon.Documents.ApplyDocumentPrefix"
               Size="MsdnVertical"
               Sequence="15" />
    </CommandUIDefinition>
    <CommandUIDefinition Location="Ribbon.Templates._children">
      <GroupTemplate Id="Ribbon.Templates.MsdnTemplate">
        ...
      </GroupTemplate>
    </CommandUIDefinition>
  </CommandUIDefinitions>
  <CommandUIHandlers />
</CommandUIExtension>

Figures 12, 13, and 14 show how just changing the <MaxSize Size="" /> attribute to the different layout options can change the rendering of the group.


Figure 12. Using the MsdnHorizontal layout

Using the MsdnHorizontal layout


Figure 13. Using the MsdnVertical layout

Using the MsdnVertical layout


Figure 14. Using the MsdnVerticalTextOnly layout

Using the MsdnVerticalTextOnly layout

Step 1.3: Add Controls to the Ribbon Group

Next, add the following markup to the element manifest file to add a few buttons to the group.
<CommandUIExtension>
  <CommandUIDefinitions>
    <CommandUIDefinition Location="Ribbon.Documents.Groups._children">
      <Group Id="Ribbon.Documents.ApplyDocumentPrefix" ... > 
        <Controls Id="Ribbon.Documents.ApplyDocumentPrefix.Controls">
          <Button Id="Ribbon.Documents.ApplyDocumentPrefix.CustomHelpButton"
                  LabelText="Apply Document Prefix Help"
                  TemplateAlias="o1"
                  Sequence="15"
                  Image16by16="/_layouts/Images/ApplyDocumentPrefixRibbon/16x16Placeholder.png"
                  Image32by32="/_layouts/Images/ApplyDocumentPrefixRibbon/32x32Placeholder.png"
                  Command="ApplyDocumentPrefix.OnGetHelpApplyDocPrefix" />
          <Button Id="Ribbon.Documents.ApplyDocumentPrefix.CustomApplyPrefixButton"
                  LabelText="Apply Prefix w/ CommandUI Handler"
                  TemplateAlias="o2"
                  Sequence="17"
                  Image16by16="/_layouts/Images/ApplyDocumentPrefixRibbon/16x16Placeholder.png"
                  Image32by32="/_layouts/Images/ApplyDocumentPrefixRibbon/32x32Placeholder.png"
                  Command="ApplyDocumentPrefix.OnApplyDocPrefixUIHandler" />
          <Button Id="Ribbon.Documents.ApplyDocumentPrefix.CustomPageComponentButton"
                  LabelText="Apply Prefix w/ Page Component"
                  TemplateAlias="o3"
                  Sequence="19"
                  Image16by16="/_layouts/Images/ApplyDocumentPrefixRibbon/16x16Placeholder.png"
                  Image32by32="/_layouts/Images/ApplyDocumentPrefixRibbon/32x32Placeholder.png"
                  Command="ApplyDocumentPrefix.OnApplyDocPrefixPageComponent" />
        </Controls>
      </Group>
    </CommandUIDefinition>
  </CommandUIDefinitions>
  <CommandUIHandlers />
</CommandUIExtension>

Notice that each button is wired to its own command. With the visual part of the ribbon customization completed, the next step is to create the commands that handle both when the buttons are available, and what they do when clicked. This is done by using command UI handlers or page components. The next two steps will show how to do each one.

Step 2: Create Server Ribbon Command UI Handlers

Command UI handlers are defined within the same element manifest file that contains the ribbon visual customizations. Add the following markup to create the first command UI handler.
<CommandUIHandlers>
  <CommandUIHandler Command="ApplyDocumentPrefix.OnGetHelpApplyDocPrefix"
      CommandAction="javascript:
        var dialogOptions = {
          url: '/_layouts/ApplyDocumentPrefixRibbon/DocPrefixHelp.aspx',
          title: 'Apply Document Prefix Help',
          allowMaximize: true,
          showClose: true,
          width:500,
          height:400
        };
        SP.UI.ModalDialog.showModalDialog(dialogOptions); " />
</CommandUIHandlers>

This command is wired to the first button by using the Command attribute. The CommandAction attribute executes some JavaScript that opens a dialog box by using the SharePoint 2010 dialog box framework that points to a custom application page that will be created later.
Add another command UI handler that will be associated with the second button. This one does considerably more work, as shown in the following markup.
<CommandUIHandlers>
  <CommandUIHandler Command="ApplyDocumentPrefix.OnGetHelpApplyDocPrefix" ... />
  <CommandUIHandler Command="ApplyDocumentPrefix.OnApplyDocPrefixUIHandler"
      CommandAction="javascript:
        function dialogCallback(dialogResult, returnValue){
          SP.UI.Notify.addNotification(returnValue);
          SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
        }
      
        var selectedItems = SP.ListOperation.Selection.getSelectedItems();
        var selectedItemIds = '';
        var selectedItemIndex;
        for (selectedItemIndex in selectedItems){
          selectedItemIds += '|' + selectedItems[selectedItemIndex].id;
        }
       
        var dialogOptions = {
          url: '/_layouts/ApplyDocumentPrefixRibbon/DocPrefixPrompt.aspx?selectedItems='
          +selectedItemIds +'&amp;ListId=' +SP.ListOperation.Selection.getSelectedList(),
          title: 'Set Document Prefix',
          allowMaximize: false,
          showClose: false,
          width:500,
          height:400,
          dialogReturnValueCallback: dialogCallback
        };
        
        SP.UI.ModalDialog.showModalDialog(dialogOptions);"
      EnabledScript="javascript:
        function checkIsEnabled(){
          // Check items selected.
          var selectedItems = SP.ListOperation.Selection.getSelectedItems();
          var count = CountDictionary(selectedItems);
          return (count > 0);
        }; 
                      
        checkIsEnabled();"
    />
</CommandUIHandlers>

This one is a bit more complicated. First, it creates a new JavaScript function that will be used as a callback when the dialog box is closed. It displays a notification in the browser, the little yellow message that slides in from the right side of the page, and then refreshes the List View Web Part on the page.
It then creates a delimited list of the documents selected on the current page. Finally, it creates a new dialog box that opens a new application page, and passes in the selected items. When the dialog box closes, it calls the dialogCallback method that was defined previously.
The other important piece to this is the EnabledScript attribute. This attribute returns a Boolean value of TRUE if the command is available or FALSE if it is not available. To determine this, it checks to see whether anything has been selected on the page. If not, the command, and so this button, is disabled.

Step 3: Create Server Ribbon Page Component

With one button in the ribbon that uses a command that is defined in a command UI handler, now it is time to create a page component to handle the other command. This is done by adding a new JavaScript file to the Visual Studio project, ideally in a folder mapped to the {SharePoint Root}/TEMPLATE/LAYOUT/{ProjectName} directory. This ensures that there is only one instance of the library on the front-end web server that is used by all sites.

Step 3.1: Declare the Page Component Object

After the file is added to the project, add the following script to the library to declare the JavaScript object that this library will contain, and a few constructor and initialization methods that will create an instance of the page component and add it to the client-side ribbon manager. This is shown in the following markup.
// Register the page component object.
Type.registerNamespace('ApplyDocumentPrefix');

// Helper methods to set up and initialize the page component.
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent = function ApplyDocumentPrefix_PageComponent() {
  ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.initializeBase(this);
}

ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.initialize = function () {
  ExecuteOrDelayUntilScriptLoaded(Function.createDelegate(null, 
  ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.initializePageComponent), 'SP.Ribbon.js');
}

ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.initializePageComponent = function () {
  var ribbonPageManager = SP.Ribbon.PageManager.get_instance();
  if (ribbonPageManager !== null) {
    ribbonPageManager.addPageComponent(ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.instance);
  }
}

Step 3.2: Create the Page Component Object Prototype and init Method

Now add the following script for the object prototype and the core init method. As its name indicates, this method initializes the object by creating a few arrays that list and map commands to specific functions within the object.
// Page component object.
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.prototype = {

  init: function ApplyDocumentPrefix_PageComponento$init() {
    // Array of commands that can be handled that are associated with handler methods.
    this.handledCommands = new Object;
    this.handledCommands['ApplyDocumentPrefix.OnApplyDocPrefixPageComponent'] = 
    this.onApplyDocPrefixPageComponent;

    // Array of commands that can be handled that are associated with canHandler methods.
    this.canHandledCommands = new Object;
    this.canHandledCommands['ApplyDocumentPrefix.OnApplyDocPrefixPageComponent'] = 
    this.onApplyDocPrefixPageComponent_canExecute;

    // Array of commands.
    this.commandList = ['ApplyDocumentPrefix.OnApplyDocPrefixPageComponent'];
  },
  getId: function ApplyDocumentPrefixPageComponent_PageComponent$getId() {
    return "ApplyDocumentPrefixPageComponent";
  },  ...
}

Notice that the name of the commands in the arrays match the value of the <Button Command="" /> attribute added previously when defining the visual components of the ribbon customization.

Step 3.3: Add Methods to Tell the Ribbon Manager What Commands This Page Component Handles, and How and When to Handle Commands

Next, add four methods that tell the client-side ribbon manager what commands are available, and how and when to handle them, as shown in the following code.
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.prototype = {
  ...
  getFocusedCommands: function ApplyDocumentPrefixPageComponent_PageComponent$getFocusedCommands() {
    return [];
  },

  getGlobalCommands: function ApplyDocumentPrefixPageComponent_PageComponent$getGlobalCommands() {
    return this.commandList;
  },

  canHandleCommand: function 
  ApplyDocumentPrefixPageComponent_PageComponent$canHandleCommand(commandID) {
    var canHandle = this.handledCommands[commandID];
    if (canHandle)
      return this.canHandledCommands[commandID]();
    else
      return false;
  },

  handleCommand: function 
  ApplyDocumentPrefixPageComponent_PageComponent$handleCommand(commandID, 
  properties, sequence) {
    return this.handledCommands[commandID](commandID, properties, sequence);
  },
  ...
}

The canHandleCommand method serves the same purpose as the command UI handler's EnabledScript attribute in that it tells the ribbon manager whether the command is available. In the previous snippet, the method uses the array created in the object's initializer to call a specific method in the object. The handleCommand is similar in that it serves the same purpose as the command UI handler's CommandAction attribute. It, too, uses an array to point to another method for the specified command.

Step 3.4: Add the Specific Command Methods

The next step is to add the methods that were defined in the object's initializer and that are called to determine when the command is available (onApplyDocPrefixPageComponent_canExecute) and what happens when the command is executed (onApplyDocPrefixPageComponent).
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.prototype = {
  ...
  onApplyDocPrefixPageComponent: function () {
    var selectedItems = SP.ListOperation.Selection.getSelectedItems();
    var selectedItemIds = '';
    var selectedItemIndex;
    for (selectedItemIndex in selectedItems) {
      selectedItemIds += '|' + selectedItems[selectedItemIndex].id;
    }

    var dialogOptions = {
      url: '/_layouts/ApplyDocumentPrefixRibbon/DocPrefixPrompt.aspx?selectedItems=' + 
      selectedItemIds + '&ListId=' + SP.ListOperation.Selection.getSelectedList(),
      title: 'Set Document Prefix',
      allowMaximize: false,
      showClose: false,
      width: 500,
      height: 400,
      dialogReturnValueCallback: PageComponentCallback
    };

    SP.UI.ModalDialog.showModalDialog(dialogOptions);
  },

  onApplyDocPrefixPageComponent_canExecute: function () {
    var selectedItems = SP.ListOperation.Selection.getSelectedItems();
    var count = CountDictionary(selectedItems);
    return (count > 0);
  }
  ...
}
function PageComponentCallback(dialogResult, returnValue) {
  SP.UI.Notify.addNotification(returnValue);
  SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
}

Step 3.5: Add Final Object Registration, Initialization, and Notification Script

With the page component object complete, the last steps are to register it on the page, create it, and tell the client-side ribbon that anything that was waiting for this script to finish loading it has been loaded and initialized. This is shown in the following code.
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.prototype = {
  ...
}
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.registerClass
('ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent', 
CUI.Page.PageComponent);
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.instance = 
new ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent();
ApplyDocumentPrefix.ApplyDocumentPrefixPageComponent.initialize();
SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("ApplyDocumentPrefix.UI.js");

At this point, the page component has been created and can now be added to the page.

Step 4: Create Server Ribbon Page Component Loader

Next, the page component must be added to the page. In this sample a custom server control is used to do this. Add a new Empty Element SharePoint project item to the project. Use the <Control /> element to register a new delegate control with the following markup.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="AdditionalPageHead"
           ControlClass="MSDN.SharePoint.Samples.ApplyDocumentPrefix.PageComponentScriptLoader"
           ControlAssembly="$SharePoint.Project.AssemblyFullName$" />
</Elements>

This will add the server control PageComponentScriptLoader to the AdditionalPageHead content placeholder to all pages in the current site, or whatever the scope of the Feature is. Now add a new code file to the SharePoint project item, and add the following code to implement the server control.
public class PageComponentScriptLoader : WebControl {
  protected override void OnPreRender(EventArgs e) {
    SPRibbon ribbon = SPRibbon.GetCurrent(this.Page);

    // Ensure ribbon exists and current list is a document library 
    // (otherwise, no need for extra ecmascript load).
    if (ribbon != null && SPContext.Current.List is SPDocumentLibrary) {
      // Load dependencies if not already on the page.
      ScriptLink.RegisterScriptAfterUI(this.Page, "SP.Ribbon.js", false, true);

      // Load page component.
.      ScriptLink.RegisterScriptAfterUI(this.Page, "ApplyDocumentPrefixRibbon/ApplyDocumentPrefix.UI.js", false, true);
    }

    base.OnPreRender(e);
  }
}

This will first get a reference to the Server ribbon. When the user is working with a document library, it will first verify that dependent scripts are on the page, followed by registering the page component.
The last step here is to add a <SafeControl /> entry to the site's web.config file. An Empty Element SharePoint project item does not automatically add a <SafeControl />entry, but it does give us a way to do to it. In Solution Explorer in Visual Studio 2010, select the Empty Element. In the Properties window, click the […] builder button, as shown in Figure 15.


Figure 15. Manually adding a Safe Control Entry with SharePoint development tools in Visual Studio 2010

Manually adding a Safe Control Entry
In the Safe Control Entries dialog box, add a new entry, and then verify that the namespace matches the namespace of the server control created earlier.


Figure 16. Safe Control Entries dialog box

Safe Control Entries dialog box

Step 5: Create the Custom Dialog Box

The last step is to create the dialog box that is called by the custom ribbon commands and that does the majority of the work. Add a new Application Page SharePoint project item to the Visual Studio project.

Step 5.1: Implement the Visual Part of the Dialog Box (.aspx)

In this case, the dialog box uses a few of the SharePoint administration form user controls, so a few references are needed, as shown in the following code.
<%@ Register TagPrefix="wssuc" TagName="InputFormSection" 
Src="~/_controltemplates/InputFormSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl" 
src="~/_controltemplates/InputFormControl.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ButtonSection" 
Src="~/_controltemplates/ButtonSection.ascx" %>

In the PlaceHolderMain content placeholder, add the following markup to create a form with an ASP.NET DataList control that will display a list of all the documents that are selected.
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
  <table border="0" cellspacing="0" cellpadding="0" width="100%">
    <tr>
      <td>
        <wssuc:InputFormSection runat="server" 
                                Title="Selected Documents" 
                                Description="The following documents have been selected 
                                to have the specified prefix added to their titles.">
          <Template_InputFormControls>
                        <tr>
                          <td>
                            <asp:DataList ID="SelectedDocumentsDataList" runat="server"
                            RepeatColumns="2" CellPadding="2" CellSpacing="5">
                  <ItemTemplate><li><%# DataBinder.Eval(Container.DataItem, 
                  "File.Name").ToString()%></li></ItemTemplate>
                </asp:DataList>
                          </td>
                        </tr>
                  </Template_InputFormControls>
        </wssuc:InputFormSection>

        <wssuc:InputFormSection runat="server" 
                                Title="Document Prefix" 
                                Description="Prefix to add to the selected document 
                                titles.">
          <Template_InputFormControls>
            <wssuc:InputFormControl LabelText="Prefix to add to the selected documents:"
            runat="server">
              <Template_control>
                <asp:TextBox ID="DocumentPrefixTextBox" runat="server" />
              </Template_control>
            </wssuc:InputFormControl>
                  </Template_InputFormControls>
        </wssuc:InputFormSection>

        <wssuc:ButtonSection runat="server" ShowStandardCancelButton="FALSE" 
        TopButtons="TRUE">
          <Template_Buttons>
            <asp:Button ID="SetPrefixButton" class="ms-ButtonHeightWidth" runat="server" 
            Text="Set Prefix" OnClick="OnClickSetPrefixButton" />
            <asp:Button ID="CancelButton" class="ms-ButtonHeightWidth" runat="server" 
            Text="Cancel" OnClientClick=
            "SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel,
            'Assignment of prefix cancelled.'); return false;" />
          </Template_Buttons>
        </wssuc:ButtonSection>
      </td>
    </tr>
  </table>
</asp:Content>

Step 5.2: Implement the Business Logic in the Code-Behind (.aspx.cs)

The code-behind for this application page is straightforward. It needs to perform the following tasks:
  • Get a list of all the selected documents that are passed in on the QueryString.
  • Get a reference to the list that contains the documents passed in on the QueryString.
  • Show the items that are selected by binding the collection of selected documents to the ASP.NET DataList control.
  • When clicked, update the file names of all the selected items.
  • When finished, write some JavaScript to the PlaceHolderAdditionalPageHead content placeholder that closes the dialog box, sending the result back to the calling page.
Add the following code to the application page's code-behind file.
public partial class DocPrefixPrompt : LayoutsPageBase {
  List<SPListItem> _selectedListItems = new List<SPListItem>();

  protected override void OnLoad(EventArgs e) {
    // Get all the selected documents.
    SPList selectedDocumentLibrary = 
        SPContext.Current.Web.Lists[new Guid(
                  Request.QueryString["ListId"]
        )];
    string[] selectedItems = 
      Request.QueryString["selectedItems"].ToString().Split('|');

    for (int index = 1; index < selectedItems.Length; index++) {
      _selectedListItems.Add(
        selectedDocumentLibrary.GetItemById(
          int.Parse(selectedItems[index]))
      );
    }

    // Bind to the repeater.
    SelectedDocumentsDataList.DataSource = _selectedListItems;
    SelectedDocumentsDataList.DataBind();
  }

  protected void OnClickSetPrefixButton(object sender, EventArgs e) {
    foreach (SPListItem listItem in _selectedListItems) {
      listItem["Name"] = 
        DocumentPrefixTextBox.Text + " " + listItem.File.Name;
      listItem.Update();
    }

    CloseDialogOnSuccess();
  }
  private void CloseDialogOnSuccess() {
    ContentPlaceHolder pageHead = this.Master.FindControl("PlaceHolderAdditionalPageHead") as ContentPlaceHolder;
    if (pageHead != null)
      pageHead.Controls.Add(
        new LiteralControl("
<script language='javascript'>
ExecuteOrDelayUntilScriptLoaded(closeDialog,'sp.js');
function closeDialog(){
  SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, 'Prefix assigned to selected documents.');
}
</script>"));
  }
}

Step 6: Deploy and Test the Custom Web Part

After saving all changes, deploy the custom Web Part by pressing F5 in Visual Studio 2010 or by clicking Start Debugging on the Debug menu.
When the initial page of the team site opens, click the Shared Documents Library. Selecting the Documents tab on the ribbon should make the ribbon customizations visible, as shown earlier in Figure 9. After a document is selected, all the buttons in the custom group will be enabled, as shown earlier in Figure 10. Clicking one of the two Apply Prefix […] buttons triggers the dialog box shown earlier in Figure 11.
When the user clicks the Set Prefix button, the dialog box updates the selected file names and then closes. The command then issues a notification message that the changes have been applied, and refreshes the List View Web Part.

Custom SharePoint 2010 Server Ribbon Development Tips and Tricks

When customizing the SharePoint 2010 Server ribbon, developers have the ability to make a wide range of changes. There are various controls that can be used, templates that could be reused, and groups and tabs that can be modified or added to. Thankfully, the majority of the ribbon is constructed declaratively or, in the case of page components, resides in script files that are easily readable compared to compiled code. This means that developers have a great supply of code samples available to them after SharePoint is installed!
The trick is knowing where to look and how to find these examples. The base Server ribbon and all the ribbon declarations can be found in the {SharePoint Root}\TEMPLATE\GLOBAL\XML\CMDUI.XML file in the global site definition. Additional changes made by things like SharePoint Server 2010 Enterprise Content Management are typically found in various Features. Simply searching all *.xml files for the <CommandUIExtension> element will show a list of all the Features that contain ribbon extensions.
The following sections help point developers in the right direction for a few common scenarios when customizing the ribbon.

Finding Tab, Group, and Control Names and Sequences

One common task is to create new tabs, add groups to tabs, or modify existing controls. The first step is finding the ID or name of the tab. The SharePoint 2010 SDK contains a list of all tabs and their locations. For more information, see Default Server Ribbon Customization Locations. The names of tabs are descriptive enough that it should be obvious which name goes with which tab. This page also contains a list of the names of all groups and controls in these groups. The only thing missing is the sequence and template alias.
To find the sequence and template alias, open the CMDUI.xml file and search for the relevant tab, group, or control ID listed in the SDK. This takes you to relevant entries that should answer any questions about the control.

Always Get a Clean Page Request: Clear the Browser Cache

When customizing the ribbon, developers will undoubtedly write JavaScript and reference images. The quantity of JavaScript and images and ribbon customizations depends on the complexity of the application.
One focus of Microsoft when refactoring the SharePoint 2010 UI and developing the ribbon was to limit the weight of the page, or the combined size of all things required on a page, as much as possible. To do this, SharePoint aggressively caches CSS files and JavaScript libraries in the browser. This in turn gives users a much faster page load time, because fewer files are requested on subsequent requests.
Although a big advantage for users, it can also create problems for developers. Changes made between debugging sessions may not appear because the browser is not downloading the latest script or customizations. As a good practice after deploying a solution and while waiting for it to load, use the Internet Explorer Developer Toolbar.


Figure 17. Clearing the IE cache and force downloads for all files 

Clearing the IE cache and force file downloads
The Internet Explorer Developer Toolbar also provides a way to explore script files. To verify that the browser has downloaded the latest version of custom script files, use theScript tab and select the script file that has been loaded by the page. If the external script file is not listed, it was not added to the page. Figure 18 shows selecting the page component external script library from a previous sample and viewing its contents.


Figure 18. Script debugging with the IE Developer Toolbar 

Script debugging with the IE Developer Toolbar

No comments:

Post a Comment