Customize the ribbon programmatically from web parts and field controls

  1. Customizing the ribbon – creating tabs, groups and controls
  2. Adding ribbon items into existing tabs/groups
  3. Ribbon customizations – dropdown controls, Client Object Model and JavaScript Page Components
  4. Customize the ribbon programmatically from web parts and field controls
In contrast to my earlier posts, this article isn’t a detailed walkthrough – rather, it is a compendium of techniques and information which should help you implement ribbon customizations for web parts, custom field controls or indeed, any other kind of page control. At the time of writing I haven’t really seen a great deal written on this, aside from a couple of resources I’ll mention. I would have loved to have written detailed walkthroughs here, but alas I can’t because a) Microsoft have recently published some good info for one of the scenarios, so I’d prefer to point you to that, b) To run through all the scenarios here in depth would take weeks and c) Because if I don’t stop writing about the ribbon soon I’ll still be on this topic this time next year, and frankly I have a  book chapter to write on a completely different area of SharePoint 2010 which I need to crack on with! So we’ll look at each requirement and I’ll discuss what I think are the key techniques you’d use along with some observations from me.
Note that due to the general lack of documentation so far on this topic (and the fact I haven’t bottomed everything out in all the scenarios), a couple of things here are speculation rather than hard fact. I’ll make these items clear, and will endeavour to come back to this article and add updates as new information emerges. 
Before we dive in, remember that if you’re abiding by ribbon design principles you should most likely be working with a ContextualGroup (discussed towards the end of Adding ribbon items into existing tabs/groups) – this is the container to use for ribbon elements which are only relevant depending on what the user is doing (shown visible but not active here):
ContextualGroup
If this isn’t what you want, note that things are probably easier if you just need to add some controls on an existing tab or group which get activated under certain circumstances. In this case you can just supply some JavaScript to the ‘EnabledScript’ attribute of your controls – I showed this in my Notifications/Status demo in Customizing the ribbon (part 1) – creating tabs, groups and controls. The rest of this article focuses on how you might get a contextual group (see image above) to show in different scenarios.
 Adding ribbon items from a web part
In SharePoint 2010 the web part framework now has special provision for ribbon customizations, which means a couple of things are taken care of for you. Microsoft have now published some guidance on this scenario in the form of an article on the SharePoint Developer Documentation blog – How to Create a Web Part with a Contextual Tab. There’s a lot of golden info in there, but I’ll distil the main points here:
  • Using server-side code, the ‘RegisterDataExtension’ method of SPRibbon can be used to pass XML to the ribbon framework.
    • This is an alternative to the fully declarative approach using the CustomAction element. As far as I can tell, either technique can be used for ribbon customizations specific to a certain control only (as opposed to ribbon customizations for say, all lists of a specific type where CustomAction is the way to go).
  • Your web part needs to implement the newIWebPartPageComponentProvider interface and it’sWebPartContextualInfo property
    • This allows you to specify information about the associated ribbon customization(s) and the ID of the associated page component (which we discussed last time) for your custom bits.This allows the ribbon framework to ‘link’ your web part with your ribbon changes – meaning that certain things are taken care of for you e.g. firing commands only when your web part has focus on the page (if you specified this behaviour by use of ‘getFocusedCommands’ in your page component). Without this you would have to write JavaScript code to manually handle page events for controls emitted by your web part e.g. the click event for a textbox.
Adding ribbon items from a field control
Like web parts, I think (speculating here) there is special provision in the framework for ribbon customizations from a field control. Consider that, like web parts, field controls should typically only show their contextual ribbon options when they have focus – since this would be the case for all field controls, it makes sense to me that Microsoft might abstract some handling around this for us. If not, you would be responsible for writing JavaScript to detect when the user clicked into your field so that you could show your ContextualGroup.
Digging around, I notice that all SharePoint field controls have 4 new properties (since they are implemented on one of the base classes,Microsoft.SharePoint.WebControls.FormComponent):
  • RibbonTabCommand
  • RibbonContextualGroupCommand
  • RibbonGroupCommand
  • RibbonCommand
I’m surmising that these control properties would be set declaratively in the hosting page and are designed to match up with commands specified in an accompanying page component – this would enable you to run client-side code similar to my sample last time, perhaps to initialize data for your ribbon controls and so on. However, when I try to implement these commands, my page component’s ‘handleCommand’ method never receives these commands. So either I’m doing something wrong or this theory is incorrect. In which case, not to worry ribbon customizations for field controls should still be entirely possible, there will just be more work to do. Read on.
Using server-side code to show ribbon items
Thinking outside of any ‘framework support’ for where our ribbon customizations are targeted at, we can always write server-side or client-side code to show a contextual group. In fact, I already showed the server-side code for this in Adding ribbon items into existing tabs/groups (ribbon customization part 2):
protected override void OnPreRender(EventArgs e)

{

    SPRibbon currentRibbon = SPRibbon.GetCurrent(this.Page);

    currentRibbon.MakeTabAvailable("COB.SharePoint.Ribbon.ContextualTab");

    currentRibbon.MakeContextualGroupInitiallyVisible("COB.SharePoint.Ribbon.ContextualGroup", string.Empty);

    

    base.OnPreRender(e);

}
This is probably only appropriate if your stuff is contextual-ish – an application page would be a good example of this. In this example all we care about is that the user is on our page, then we can show our options. It doesn’t matter which control has focus, effectively our options are OK to show by default when the page loads. However, if you need page-level ‘contextuality’ (I may have just invented that word by the way – use it in a sentence to your boss today) then most likely you’ll be wanting to use JavaScript to show your contextual group when the user is doing something specific on the page e.g. editing a certain field. You’d then be looking to some client-side code to detect this and respond accordingly.  
Using client-side code to show ribbon items
So, final scenario – what if you need to show ribbon items from something which isn’t a web part or field control (or like me you couldn’t get there with anything in the field control framework which may or may not be designed to help), and it has to be done client-side to be fully contextual? Well, disappointingly I’m drawing another blank here so far – I’d love to hear from anyone who knows the answer to this. In case you’re doing ribbon development and are interested, here’s a summary of my journey:
  • Checked SP.Ribbon namespace in Client OM
  • Spent many happy hours in the debugger and various out-of-the-box JavaScript files, looking for examples of where the core product does this (e.g. calendar, rich text editor to name a couple)
  • Found some interesting methods on the CUI.Ribbon object, such as showContextualGroup(‘foo’) and selectTabByCommand(‘bar’)
    • Noted that across the entire SharePoint root, these methods are only called by the RTE, not globally across the SharePoint codebase
    • Noted that the RTE code gets a CUI.Ribbon instance from a property (RTE.RichTextEditorComponent.$3b() – N.B. most of the JS is obfuscated or machine-generated* down here)
  • Tried to use SP.Ribbon.PageManager.get_instance().get_ribbon() (used elsewhere in the OOTB codebase) to get me a CUI.Ribbon instance, however this gave me a null
  • Tried to use the ‘_ribbon’ page level variable, however this appears not to be of type CUI.Ribbon as the debugger shows it does not have the methods I’m trying to call
  • Tried a couple of other things which I’ve forgotten now
Needless to say, I’d love to hear what I’m missing on this. If nothing else, hopefully MS will release some more information soon which will shed some light on how to handle this scenario.
Summary
This post doesn’t claim to have all the answers, but it might serve as a “leg up” if you’re trying to build any of these scenarios now. I’m hoping that the lack of deep information in this area is a reflection on the fact that RTM is still some time away, and that ribbon dev will get some love in the SDK between now and then. The key scenarios I discussed here are displaying custom ribbon elements from web parts and field controls, but also the more generic cases of displaying customizations with server or client-side code.

SharePoint 2010: Get Full or Relative Url of web using EcmaScript

Sometimes from client side, you need to know the current web url. And for this little information you don’t want to call EcmaScript’s load function to get information from server side. Actually the information can be found without any server call. You can access the information from ClientContext as shown below.
var context = new SP.ClientContext();
var relativeWebUrl = context.get_url();
Remember the get_url method will only return relative url of the site. As shown in the following table:
Site Collection UrlSite Urlcontext.get_url() response
http://mysite.comhttp://mysite.com/
http://mysite.comhttp://mysite.com/site1/site1
http://mysite.com/siteshttp://mysite.com/sites/site1/sites/site
So if you need to know the full url of the site you can do so easily with the following script:
function getFullWebUrl() {
    var context = new SP.ClientContext();
    var relativeWebUrl = context.get_url();
    var fullWebUrl = window.location.protocol + '//' + window.location.host + relativeWebUrl ;
    alert(fullWebUrl);
} 

SharePoint 2010: Conditional Scope

In Client Object Model, if you need to load data based on some condition. But if the condition is based on some server side values then you need to use two different requests. First request will be to get the values from the server to check the condition. Second request will be to load data or not, based on the condition expression value.
In SharePoint Client Object Model API, there’s a new class called ConditionalScope to load data conditionally. Here’s how to use the ConditionalScope:
  • In ConditionalScope constructor pass the ClientContext instance as first parameter. In the second parameter, pass the condition to be evaluated on the server. As shown below, the condition to check is whether the list is hidden or not.
var conditionalScope = new ConditionalScope(clientContext, () => !list.Hidden);
  • The second step is to put the load expression in ConditionalScope’s StartScope method. As shown below, if the list is not hidden, then load the Title of the list.
using (conditionalScope.StartScope())
{
    clientContext.Load(list, ol => ol.Title);
}
In the above statement, the load will be executed if the condition specified in ConditionalScope’s constructor is true (in this case, not hidden).
  • Finally, after executing ClientContext.ExecutQuery method, you need to find out if the expression passed in Coditional Scope was true or false. If condition was true then u know the data has been loaded (in this case the title of the list). If the condition was not true then data was not loaded. To check whether the condition evaluated true of false, check conditional scope’s TestResult. Remember, you will only get this property value after executing Executing query to the server.
clientContext.ExecuteQuery();
if (conditionalScope.TestResult.HasValue && conditionalScope.TestResult.Value)
{
    Console.WriteLine("Title:" + list.Title);
}
As shown in the code snippet above, if the TestResult has been evaluated to true then the title property is available.
The whole code will look like below:
var clientContext = new ClientContext(siteUrl);
var web = clientContext.Web;
var list = web.Lists.GetByTitle(listName);

var conditionalScope = new ConditionalScope(clientContext, () => !list.Hidden);

using (conditionalScope.StartScope())
{
    clientContext.Load(list, ol => ol.Title);
}

clientContext.ExecuteQuery();
if (conditionalScope.TestResult.HasValue && conditionalScope.TestResult.Value)
{
    Console.WriteLine("Title:" + list.Title);
}

 

Limitations

You can not use Conditional scope in all cases for all operations:
  • You can only load data using Conditional Scope. You can not however call any method or set properties in Conditional Scope’s StartScope method. If you use the ConditionalScope to set properties or to call server side method, you may get the following error:
Incorrect usage of conditional scope. Some actions, such as setting a property or invoking a method, are not allowed inside a conditional scope.
  • expression passed in ConditionalScope’s second argument has restrictions. You can not use all kinds of expressions. For example you can not use expression like, list.Fields.Count. However, you can use List.ItemCount. I have not found any documentation on MSDN with the supported expression for ConditionalScope.
  • Before using ConditionalScope.TestResult in your decision to access data, you need to execute Query.

SharePoint 2010 Client Object Model: Manipulate Choice, Lookup field

After my few posts on Client Object Model, I had come to questions on how to manipulate choice and lookup field. I’ve tried to explain a bit on how you can manipulate these field values with Client Object Model.

Manipulate Choice Field Value (Single Choice)

You can manipulate the single choice field value as like string. For example, let’s consider a field, ProductStatus in Product list. The field values might be “In Stock, Out of Stock, Invalid” as shown below:
image
Figure 1: Single Choice Field (ProductStatus) in product list.
To access the value of the field using Client Object Model, you can use code shown below:
  • Get Field value: You can just get the field value as string
    var productStatus = productItem["ProductStatus"].ToString();
  • Set Field value: You can use any of the following statement to set the field value
    productItem["ProductStatus"] = "In Stock";
    productItem["ProductStatus"] = "Out of Stock";
    productItem["ProductStatus"] = "Invalid";

Manipulate Choice Field Value (Multiple Choice)

If the choice field support multiple values then you need to use string array to manipulate field values. For example, consider there’s a field ‘product types’  in product list whose values can be Foods, electronics, Cars etc. Also consider the field values can be multiple, that’s mean a product types can be more than one type. The following figure shows the field
image
Figure 2: Multiple Choice Field
In that case you need string array to access the multiple choice field value as shown as shown below:
  • Get Field Value:
    var productTypes = (string[]) (productItem["ProductType"]);
  • Set Field Value:
    productItem["ProductType"] = new string[] { "Furniture", "Toys" };

Manipulate Lookup Field Value

To manipulate lookup field you need to use the code as shown below:
  • Get Field Value:
    var lookupFieldValue = (productItem["FieldName"] as FieldLookupValue);
  • Set Field Value
    //100 here is the lookup field id value
    productItem["FieldName"] = new FieldLookupValue(){LookupId = 100};
The FieldLookupValue is part of SharePoint Client OM