One of the cool new features in SharePoint 2010 is the availability of the Office Ribbon. Using the simple XML syntax, it is quite easy to add your own Ribbon controls and tabs to existing lists, libraries, and even your own web parts. You can even add contextual ribbon tabs to web parts hosted in your own custom Application Pages.
Now it’s easy to get a “global” Ribbon by simply omitting the RegistrationId and RegistrationType attributes in the Elements.xml file. You’ll find ways of doing this in tons of blog posts all over. What is not so obvious, however, is the way to do add a Ribbon to a particular Application Page when the page does not host any Web part or user control. So here’s some help for you. I’ll also take a look at interacting with a modal dialog using the new framework in SharePoint from this ribbon.
First, open up VS2010 and create an Empty SharePoint Project (make sure it’s 2010, not 2007). Next add a reference to the Microsoft.Web.CommandUI assembly as it will be needed later on.
Now create a new Application Page by right-clicking the project and adding a new item. Name it DataPage.aspx. This will get created as Layouts/<Project name>/DataPage.aspx. Now comes the interesting part. Create the ribbon by declaring two strings that hold the Tab and the GroupTemplate definitions like this:
private string mainTab = @"
<Tab
Id=""Ribbon.MyTab""
Title=""My Tab""
Description=""This is a sample tab""
Sequence=""1105"">
<Scaling
Id=""Ribbon.MyTab.Scaling"">
<MaxSize
Id=""Ribbon.MyTab.MaxSize""
GroupId=""Ribbon.MyTab.MyGrp""
Size=""OneLargeTwoMedium""/>
<Scale
Id=""Ribbon.MyTab.Scaling.CustomTabScaling""
GroupId=""Ribbon.MyTab.MyGrp""
Size=""OneLargeTwoMedium"" />
</Scaling>
<Groups Id=""Ribbon.MyTab.Groups"">
<Group
Id=""Ribbon.MyTab.MyGrp""
Description=""This is a sample group!""
Title=""Sample Group""
Sequence=""52""
Template=""Ribbon.Templates.MyGrp"">
<Controls
Id=""Ribbon.MyTab.MyGrp.Controls"">
<Button
Id=""Ribbon.MyTab.MyGrp.ModalDialog""
Sequence=""15""
Description=""Opens a modal dialog box""
Command=""Ribbon.MyTab.MyGrp.ModalDialog.Click""
Image32by32=""/_layouts/images/PPEOPLE.GIF""
LabelText=""Open Modal Dialog""
TemplateAlias=""cust1""/>
<Button
Id=""Ribbon.MyTab.MyGrp.SimpleButton""
Sequence=""17""
Image32by32=""/_layouts/images/PPEOPLE.GIF""
Description=""Simple alert button""
Command=""Ribbon.MyTab.MyGrp.SimpleButton.Click""
LabelText=""Simple Alert""
TemplateAlias=""cust2""/>
</Controls>
</Group>
</Groups>
</Tab>";
private string contextualTabTemplate = @"
<GroupTemplate Id=""Ribbon.Templates.MyGrp"">
<Layout
Title=""OneLargeTwoMedium"" LayoutTitle=""OneLargeTwoMedium"">
<Section Alignment=""Top"" Type=""OneRow"">
<Row>
<ControlRef DisplayMode=""Large"" TemplateAlias=""cust1"" />
<ControlRef DisplayMode=""Large"" TemplateAlias=""cust2"" />
</Row>
</Section>
</Layout>
</GroupTemplate>";
As you can make out, this defines a new tab with two button controls on it. Now create a OnPreRender event for the page and the following code, like so:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
this.AddRibbonTab();
AddTabEvents();
}
private void AddRibbonTab()
{
// Gets the current instance of the ribbon on the page.
SPRibbon ribbon = SPRibbon.GetCurrent(this.Page);
//Prepares an XmlDocument object used to load the ribbon
XmlDocument ribbonExtensions = new XmlDocument();
//Load the contextual tab XML and register the ribbon.
ribbonExtensions.LoadXml(this.mainTab);
ribbon.RegisterDataExtension(ribbonExtensions.FirstChild,
"Ribbon.Tabs._children");
//Load the custom templates and register the ribbon.
ribbonExtensions.LoadXml(this.contextualTabTemplate);
ribbon.RegisterDataExtension(ribbonExtensions.FirstChild,
"Ribbon.Templates._children");
ribbon.Minimized = false;
ribbon.CommandUIVisible = true;
const string initialTabId = "Ribbon.MyTab";
if (!ribbon.IsTabAvailable(initialTabId))
ribbon.MakeTabAvailable(initialTabId);
ribbon.InitialTabId = initialTabId;
}
private void AddTabEvents()
{
var commands = new List<IRibbonCommand>();
// register the command at the ribbon. Include the callback to the server
// to generate the xml
commands.Add(new SPRibbonCommand("Ribbon.MyTab.MyGrp.ModalDialog.Click",
"openPopup();", "true"));
commands.Add(new SPRibbonCommand("Ribbon.MyTab.MyGrp.SimpleButton.Click",
"alert('goodbye cruel world');", "true"));
//Register initialize function
var manager = new SPRibbonScriptManager();
var methodInfo = typeof(SPRibbonScriptManager).GetMethod(
"RegisterInitializeFunction",
BindingFlags.Instance | BindingFlags.NonPublic);
methodInfo.Invoke(manager, new object[] {
Page, "InitPageComponent",
"/_layouts/SPSample/PageComponent.js", false,
"SPSample.PageComponent.initialize()" });
// Register ribbon scripts
manager.RegisterGetCommandsFunction(Page, "getGlobalCommands", commands);
manager.RegisterCommandEnabledFunction(Page, "commandEnabled", commands);
manager.RegisterHandleCommandFunction(Page, "handleCommand", commands);
}
The code, though a little long, is actually quite simple and can be reused almost completely for any number of ribbons. The first function simply adds the display of the ribbon while the second registers the JavaScript to call when the respective buttons’ click commands are called. The Ribbon button event handling requires some extra JavaScript as well that is loaded within another .JS file. To do this, simply add a new JavaScript file in the same location and call it PageComponent.js. This is what it’ll look like.
function ULS_SP() {
if (ULS_SP.caller) {
ULS_SP.caller.ULSTeamName = "Windows SharePoint Services 4";
ULS_SP.caller.ULSFileName = "/_layouts/SPSample/PageComponent.js";
}
}
Type.registerNamespace('SPSample');
// RibbonApp Page Component
SPSample.PageComponent = function () {
ULS_SP();
SPSample.PageComponent.initializeBase(this);
}
SPSample.PageComponent.initialize = function () {
ULS_SP();
ExecuteOrDelayUntilScriptLoaded(Function.createDelegate(null,
SPSample.PageComponent.initializePageComponent), 'SP.Ribbon.js');
}
SPSample.PageComponent.initializePageComponent = function () {
ULS_SP();
var ribbonPageManager = SP.Ribbon.PageManager.get_instance();
if (null !== ribbonPageManager) {
ribbonPageManager.addPageComponent(SPSample.PageComponent.instance);
ribbonPageManager.get_focusManager().requestFocusForComponent(
SPSample.PageComponent.instance);
}
}
SPSample.PageComponent.refreshRibbonStatus = function () {
SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand(
Commands.CommandIds.ApplicationStateChanged, null);
}
SPSample.PageComponent.prototype = {
getFocusedCommands: function () {
ULS_SP();
return [];
},
getGlobalCommands: function () {
ULS_SP();
return getGlobalCommands();
},
isFocusable: function () {
ULS_SP();
return true;
},
receiveFocus: function () {
ULS_SP();
return true;
},
yieldFocus: function () {
ULS_SP();
return true;
},
canHandleCommand: function (commandId) {
ULS_SP();
return commandEnabled(commandId);
},
handleCommand: function (commandId, properties, sequence) {
ULS_SP();
return handleCommand(commandId, properties, sequence);
}
}
// Register classes
SPSample.PageComponent.registerClass('SPSample.PageComponent',
CUI.Page.PageComponent);
SPSample.PageComponent.instance = new SPSample.PageComponent();
// Notify waiting jobs
NotifyScriptLoadedAndExecuteWaitingJobs("/_layouts/SPSample/PageComponent.js");
This code can be used as-is – other than changing the namespace (from “SPSample” in my case to whatever your code project is called).
This is actually enough for the application page to show the ribbon and have two buttons on it. The second button will in fact work fine and give an alert popup as well. For the first button, we need to use the SharePoint 2010 Modal Dialog framework. All you need to do is open the DataPage.aspx file and add the following into the PlaceHolderAdditionalPageHead.
<script language="javascript">
function demoCallback(dialogResult, returnValue)
{
if (dialogResult == SP.UI.DialogResult.OK)
SP.UI.Notify.addNotification("You pressed OK, " + returnValue, false);
else
SP.UI.Notify.addNotification("You cancelled the operation, ", false);
}
function openPopup()
{
var options = {
url: '/_layouts/SPSample/DialogPage.aspx',
title: 'Modal Dialog',
allowMaximize: false,
showClose: true,
width: 600,
height: 500,
dialogReturnValueCallback: demoCallback
}
SP.UI.ModalDialog.showModalDialog(options);
}
</script>
Create a new Application Page and call it DialogPage.aspx. Add the following to create a simple form in the PlaceHolderMain:
<h1>Dialog popup page</h1>
<p>Please enter your name:<br />
<asp:TextBox runat="server" ID="txtFullName" /><br />
<asp:Button runat="server" ID="btnOKClient"
OnClientClick="btnOKClient_Click()" Text="OK (Client)" />
<asp:Button runat="server" ID="btnOKServer"
OnClick="btnOKServer_Click" Text="OK (Server)" />
<asp:Button runat="server" ID="btnCancel"
OnClientClick="btnCancel_Click()" Text="Cancel" />
</p>
This code shows a small form with one textbox and 3 buttons. The first button closes the modal dialog using the client OM directly, the second submits the form back to the server and then closes the dialog and the third simply cancels the dialog.
You will also need to add the following script in the PlaceHolderAdditionalPageHead area in the DialogPage.aspx:
<script type="text/javascript">
function btnCancel_Click()
{
SP.UI.ModalDialog.commonModalDialogClose
(SP.UI.DialogResult.cancel, "Cancelled");
}
function btnOKClient_Click()
{
var theForm = document.forms['aspnetForm'];
if (!theForm)
{
theForm = document.aspnetForm;
}
var FullName = theForm.<%= txtFullName.ClientID %>.value;
SP.UI.ModalDialog.commonModalDialogClose(
SP.UI.DialogResult.OK, FullName + " (Client)");
}
</script>
This code simply cancels the dialog on the cancel click and the on the client OK click, gets the name entered in the dialog and posts it back to show the notification.
In the code behind of the DialogPage.aspx, add an event handler for the “OK (Server)” button which looks like this:
this.Page.Response.Clear();
this.Page.Response.Write(
String.Format("<script>
window.frameElement.commonModalDialogClose(1, '{0} (Server)')
</script>", txtFullName.Text));
this.Page.Response.End();
You can do whatever you want in the codebehind and once done, use the code above to close the dialog and send some result (in this case the same name entered in the textbox) back to the parent page.
And finally, some screenshots of how it all looks.
The custom Application Page with a custom Ribbon Tab and buttons
Clicking the “Simple Alert” button on the Tab shows, well, a simple JS alert
Clicking the “Open Modal Dialog” button open a modal dialog with another application page
The “Cancel” button in the modal dialog closes and shows a Notification message in the parent
The “OK (Client)” button in the dialog, closes the dialog and sends a notification using JS
The “OK (Server)” button submits the dialog to the server and the codebehind sends a notification back
Hope you find this useful. A big thanks to all those good people on the Web who have provided code ideas and snippets used in this article. Sorry I’m not linking to any of them as they were found while Binging around. Also, here is the entire VS2010 project in case you need it.
Tags:
sharepoint,
development,
office,
asp.net
Categories:
Development |
Office |
SharePoint