Lets put together a Ribbon Project which demonstrates my last post.
Create an empty SharePoint Project, here named testRibbonCommunications:

Add New Item

-
-
-
-
Choose Application Page (I named this TestRibbon.aspx)


Add the following code in a PageComponent.js file to your layouts folder and change the namespace to fit your project (testRibbonCommunications) just do a find / replace:
/// <reference name="MicrosoftAjax.js" />
/// <reference path="file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.core.debug.js" />
/// <reference path="file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.debug.js" />
function ULS_SP() {
if (ULS_SP.caller) {
ULS_SP.caller.ULSTeamName = "Windows SharePoint Services 4";
ULS_SP.caller.ULSFileName = "/_layouts/testRibbonCommunications/PageComponent.js";
}
}
Type.registerNamespace('testRibbonCommunications');
// RibbonApp Page Component
CaseSmartIntakeForm.PageComponent = function () {
ULS_SP();
CaseSmartIntakeForm.PageComponent.initializeBase(this);
}
CaseSmartIntakeForm.PageComponent.initialize = function () {
ULS_SP();
ExecuteOrDelayUntilScriptLoaded(Function.createDelegate(null, testRibbonCommunications.PageComponent.initializePageComponent), 'SP.Ribbon.js');
}
testRibbonCommunications.PageComponent.initializePageComponent = function () {
ULS_SP();
var ribbonPageManager = SP.Ribbon.PageManager.get_instance();
if (null !== ribbonPageManager) {
ribbonPageManager.addPageComponent(testRibbonCommunications.PageComponent.instance);
ribbonPageManager.get_focusManager().requestFocusForComponent(testRibbonCommunications.PageComponent.instance);
}
}
testRibbonCommunications.PageComponent.refreshRibbonStatus = function () {
SP.Ribbon.PageManager.get_instance().get_commandDispatcher().executeCommand(Commands.CommandIds.ApplicationStateChanged, null);
}
testRibbonCommunications.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
testRibbonCommunications.PageComponent.registerClass('testRibbonCommunications.PageComponent', CUI.Page.PageComponent);
testRibbonCommunications.PageComponent.instance = new testRibbonCommunications.PageComponent();
// Notify waiting jobs
NotifyScriptLoadedAndExecuteWaitingJobs("/_layouts/testRibbonCommunications/PageComponent.js");
In the code behind for your application page add the ICallbackEventHandler Interface to the page code behind:
namespace testRibbonCommunications.Layouts.testRibbonCommunications
{
public partial class TestRibbon : LayoutsPageBase, ICallbackEventHandler
{
protected void Page_Load(object sender, EventArgs e)
{
}
public string GetCallbackResult()
{
throw new NotImplementedException();
}
public void RaiseCallbackEvent(string eventArgument)
{
throw new NotImplementedException();
}
}
}
The XML is terse but once you have done one tab and button you can do them all.
Add the following region to the code behind of the application page (A tab with a single button):
#region tabxml
private string mainTab = @"
<Tab
Id=""Ribbon.MyTab""
Title=""Daves Tab""
Description=""Daves 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=""Actions""
Title=""Status""
Sequence=""52""
Template=""Ribbon.Templates.MyGrp"">
<Controls>
<Button
Id=""Ribbon.MyTab.MyGrp.Save""
Sequence=""56""
Image32by32=""/_layouts/1033/images/formatmap32x32.png""
Image32by32Top=""-416""
Image32by32Left=""-256""
Description=""Save Button""
Command=""Ribbon.MyTab.MyGrp.Save.Click""
LabelText=""""
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=""cust2"" />
</Row>
</Section>
</Layout>
</GroupTemplate>";
#endregion
Add the following region to the code behind of the application page:
#region tabMethods
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.MyFormGrp.Save.Click", "setSave();", "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/testRibbonCommunications/PageComponent.js", false,
"testRibbonCommunications.PageComponent.initialize()" });
// Register ribbon scripts
manager.RegisterGetCommandsFunction(Page, "getGlobalCommands", commands);
manager.RegisterCommandEnabledFunction(Page, "commandEnabled", commands);
manager.RegisterHandleCommandFunction(Page, "handleCommand", commands);
}
#endregion
Add the following region to the code behind of the application page:
#region pageEvents
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
this.AddRibbonTab();
AddTabEvents();
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
String callbackScript;
callbackScript = "function CallServer(arg, context)" +
"{ " + cbReference + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"CallServer", callbackScript, true);
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
#endregion
The above code blocks tie the ribbon pieces together
Add a JavaScript Page to the solution in the Layouts folder (PageScript.js):
function setSave() {
//call server
SP.UI.Notify.addNotification("You pressed Save, ", false);
CallServer("Save", "");
}
// variable to hold the server data
var itemsXml;
// This function will receive the callback from the server with the data.
function ReceiveServerData(arg, context) {
itemsXml = arg;
}
Link the JavaScript file to the page by adding this to the page AdditionalPageHead section: use your page URL
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<SharePoint:ScriptLink Name="sp.js" LoadAfterUI="true" OnDemand="false" Localizable="false" runat="server" ID="ScriptLink1" />
<SharePoint:ScriptLink Name="CUI.js" LoadAfterUI="true" OnDemand="false" Localizable="false" runat="server" ID="ScriptLink2" />
<SharePoint:ScriptLink Name="/_layouts/testRibbonCommunications/PageComponent.js" LoadAfterUI="true" OnDemand="false" Localizable="false" runat="server" ID="ScriptLink3" />
<SharePoint:ScriptLink Name="/_layouts/testRibbonCommunications/pageScript.js" LoadAfterUI="true" OnDemand="false" Localizable="false" runat="server" ID="ScriptLink4" />
</asp:Content>
Replace the ICallbackEventHandler methods with this region:
#region ICallbackEventHandler Members
public string GetCallbackResult()
{
//I am returning nothing
string returnData = "Call Back Results";
return returnData;
}
public void RaiseCallbackEvent(string eventArgument)
{
if (eventArgument.Contains("Save"))
{
//handle the save event here
}
}
#endregion
Deploy the solution and browse to the page:

Everything should be good to go!
Set a Breakpoint at the RaiseCallbackEvent(string eventArgument) and hit F5 Browse to the layouts page and click the save button, Notice the breakpoint get hit and enters the empty test.

There you have it! Here is the solution for you to build on! TestRibbonCommunications