Monday, January 25, 2010

Project Server JS customization: Sample of webpart callback interface implementation

In the previous post “SharePoint 2010 webpart callback interface” we have considered new SharePoint client-server interoperation model and the asynchronous callback interface implementation on the client.

In this post we provide a complete server-side webpart C# class that implements ICallbackEventHandler interface and generates all necessary JavaScript code for the interoperation.

public class CustomWebPart : Microsoft.SharePoint.WebPartPages.WebPart, ICallbackEventHandler
    private string _result = String.Empty;

    #region ICallbackEventHandler members

    public void RaiseCallbackEvent(string eventArgument)
            // Save logic
            // eventArgument can be all webpart fields data in JSON
        catch (Exception ex)
            _result = ex.Message;

    public string GetCallbackResult()
        return _result;


    protected override void OnPreRender(EventArgs e)
        //register script for hooking up into the PDP structure
        string uniqueScriptName = "PDP Class " + ClientID;
        string callBackScript = Page.ClientScript.GetCallbackEventReference(
            string.Format("SaveCallback_{0}", ClientID),
            string.Format("SaveErrorCallback_{0}", ClientID), false);

        string script =
                @"var WPDP_{0} =  new object();
       WPDP_{0}.IsDirty = false;
                  // Controls webpart’s state
                  WPDP_{0}.EnablePart = function pfp_EnablePart_{0}(enabled) {{
                      // Can pass “enable” argument value to other methods

                  // Initiates Save operation
                  WPDP_{0}.Save = function pfp_Save_{0}(ctx) {{
                      var arg = ConstructArg_{0}();

                  // Performs client validation
                  WPDP_{0}.Validate = function pfp_Validate_{0}() {{
                      return true;

                  function SaveCallback_{0}(result, ctx) {{
                      if (result != '') {{
                          SaveErrorCallback_{0}(result, ctx);
                      else {{

                  function SaveErrorCallback_{0}(result, ctx) {{
                  // Collects and returns webpart’s client data
                  function ConstructArg_{0}() {{
                      return “some data”;

        Page.ClientScript.RegisterClientScriptBlock(GetType(), uniqueScriptName, script, true);

The class should implement ICallbackEventHandler interface. The RaiseCallbackEvent method accepts a string argument that should be a representation of the client data to be processed on the server side. The operation result is to be returned to the client side using the GetCallbackResult method call. As the operation result is not returned directly by RaiseCallbackEvent method, it should be stored within the class between the calls. On the client side the operation result is accepted by the “SaveCallback” JS method.

The JS object and all its methods’ names are unique due to the “ClientID” property. The “Save” JS method constructs the argument (using the “ConstructArg” JS method) and passes it to the callback script which actually initiates the client-server interoperation.

Next time we will talk of the out-of-box Project Fields webpart and the client JavaScript code it generates.


  1. Hi there , I have try your example here. But I couldn't get call back when I click the save ribbon. What could be the issue here?