Customizing the Microsoft CRM Ribbon: Ribbon Workbench Solution

ribbon_workbench_main

Note: I originally posted this at cobalt.net

I’ve been customizing and developing for Microsoft CRM for 10 years now and the most frustrating experiences I’ve had are all related to customizing the ribbon. Microsoft expanded the functionality available through the ribbon, but you couldn’t leverage any of it without manually updating the customizations XML. When CRM 2011 was introduced I found myself spending entire afternoons poring over Microsoft references trying to figure out exactly which XML nodes and attributes I needed to add to make a simple button do what I needed it to. I knew there had to be a better way; and eventually I found it.

Scott Durow (of Develop1) has written a fantastic Solution for CRM 2011, CRM 2013 and CRM 2015 which really helps simplify the customization process. By using a slick drag and drop interface, the Ribbon Workbench Solution can easily help you tailor the CRM ribbon to fit your needs. In this post I’m going to run through a simple scenario of customizing the contact form to add a button which invokes a custom JavaScript function.

The Ribbon Workbench Solution is free and available for download from Develop1 at https://ribbonworkbench.uservoice.com.

Creating a Working Solution

The workbench works by opening an existing unmanaged solution, adding in your changes, and then re-importing and publishing the solution. If you don’t already have a solution with your customizations, the first step is to create a new working solution with everything required by your new ribbon button. In my example, I have the Contact entity, two icons for the new button (16×16 and 32×32) and a simple JavaScript resource with the method I’m going to call.

ribbon_1

Here’s the function in my JavaScript resource, which gets the primary attribute from the contact (the full name) and alerts to the page. It’s not the most practical example but it’s easy to illustrate the behavior.

function AlertPrimaryValue() {

 var primaryValue = Xrm.Page.data.entity.getPrimaryAttributeValue();

 alert(primaryValue);

}

Open Your Solution for Editing

Open the Ribbon Workbench by navigating to the Solutions section of the Settings menu, and clicking on the Ribbon Workbench button.

ribbon_2.png

When the Ribbon Workbench opens, the first thing you’ll see is a list of all the unmanaged solutions that can be modified. Pick the solution we created that has all the required resources and hit OK.
ribbon_3.png
Side Note: The other solution listed is Dynamics CRM Snapshot, a free utility we’ve developed at Cobalt to help you take backups, restore from a backup to a point in time, clone, or restore a deleted record in CRM.

The main steps to create a new button are to create the command you want to run, create the button to initiate the command, and publishing the changes.

Create a Command to Call the JavaScript

When you solution opens (numbered for the image below)

  1. Select the entity that you’re going to update
  2. Right click on Commands
  3. Click Add New

A new command will be added to the Commands section.

ribbon_4

To associate a specific action with that command:

  1. Select the command to update
  2. Give the Id field a distinct, descriptive name. In this example, cobalt.contact.JavaScriptExample
  3. Click on the magnifying glass next to actions to build the action

ribbon_5

A new pop-up will open showing you a list of all the actions you’ve created for this entity. Since we haven’t created any yet the list is blank and you’ll select Add. The next prompt is for which kind of action you want to perform, either call JavaScript or open a URL.

ribbon_6

Select JavaScript, then type in the function name and Library that you created earlier and hit OK.

ribbon_7

Create the Button to Call Your JavaScript

Now that we’re ready to add the button to the form, we just need to drag and drop a button on the ribbon and set a handful of properties.

ribbon_8.png

Click on the new button in the ribbon and set a few key properties.

  1. Command – Select the command that was just created
  2. Images – You can select the images based on the Web Resources that are included in the solution you selected when you opened the workbench
  3. Labels – These properties are for the text you see on the button. Each property is for something slightly different but in this example I’m going to make them all the same thing.

ribbon_9.png

After making all your changes you should see your button updated with the new image and text. When you’re satisfied with your changes, hit Publish at the top of the screen. If everything goes well then you’ll be able to open a contact record and see and click on your new button:

ribbon_10.png

ribbon_11.png

Conclusion

The Microsoft Dynamics CRM team has given us a lot of flexibility to configure the ribbon but out of the box there isn’t an easy way to customize the ribbon to add buttons. The team at Develop1 has done a great job building a tool that greatly simplifies a complex process to the point where a non-technical user can now add functionality without having to reference the XML schema document. The Ribbon Workbench Solution has saved me countless hours, and I hope it will help you too.

Improving Performance of CRM Forms with IFrames

Note: I originally published this at cobalt.net

Microsoft Dynamics CRM has long supported Iframes on forms but the way they’re implemented usually has a negative impact on form load times. While I was researching the form load process in CRM, I came across a great topic on MSDN which describes how Iframes should be loaded for best performance. The article at ‘Write code for Microsoft Dynamics CRM forms’ (http://msdn.microsoft.com/en-us/library/gg328261.aspx) suggests using collapsed tabs to defer loading web resources, which means we can eliminate the load times for Iframes completely if you’re not going to use it. The idea is, instead of setting the Iframe URL in OnLoad you use the TabStateChange event, which fires when the Tab is expanded and collapsed.

To implement this we need to add a Javascript web resource for setting the URL, the form customizations with the tab and Iframe, and update the tab event to call the Javascript. In this scenario we’re going to set up an Iframe to show an Account’s website.

Setting up the Web Resource

Go to your default (or named) solution and add a new Web Resource of type Script (Jscript). The name of my script is cobalt_DeferredFormLoad. After saving the resource, click on the Text Editor button to enter your script.

improving-performance-of-crm-forms-with-iframes1.jpg

This is the script I’m using to set the URL. It’s quasi-generic, and will work for any entity where there is a website field on the form. The function takes in the name of the tab, the frame, and the attribute of the website.

function LoadIFrame(tabName, iframeName, websiteAttribute) {
if (tabName != null && iframeName != null && websiteAttribute!= null ) {
var isTabExpanded = (Xrm.Page.ui.tabs.get(tabName).getDisplayState() == “expanded”);
var websiteUrl = Xrm.Page.getAttribute(“websiteurl”).getValue();
if (isTabExpanded == true && websiteUrl) {
var IFrame = Xrm.Page.ui.controls.get(iframeName);
if (IFrame != null) {
IFrame.setSrc(websiteUrl);
}
}
}

}

Adding the Form Customizations

From the Account form, insert a new Tab and leave the default values. Click in the Section area of the new tab and insert a new Iframe from the Ribbon Bar. Give the frame an appropriate name (IFRAME_CompanyWebsite) and any default URL. I unchecked ‘Display label on the Form’ because the tab label looks good on its own.

improving-performance-of-crm-forms-with-iframes2.jpg

Now that the Iframe is setup you need to configure the Tab properties to load the Iframe. Under the Display tab, give an appropriate name and label, and uncheck ‘Expand this tab by default’.

improving-performance-of-crm-forms-with-iframes3.jpg

Configuring the Event

With the Tab properties open, go to the Events tab, Add your new web resource, then Add a new Event Handler

improving-performance-of-crm-forms-with-iframes4.jpg

In the Event Handler screen, fill in the name of the Function from the Javascript (LoadIFrame), and in the parameters section, list the parameters that need to be passed in the to function. The parameters are the name of the Tab, the name of the Iframe, and the name of the field that contains the URL to set. Remember that you’re specifying a string value and each parameter should be enclosed with a single quote mark.

improving-performance-of-crm-forms-with-iframes5.jpg

Once you save and publish the customizations you can verify the results on your entity. Open the account form and find your new Tab, expand it, and verify everything opens correctly.

Miscellaneous Notes

  • If your CRM instance uses SSL and the Iframe src doesn’t, then you may receive a warning from your browser (or no information at all). You will need to adjust your security settings.
  • You can easily update the Javascript function to not take any parameters and hardcode the tab, frame, and URL. I set it up this way so you could use it on other forms (contact, lead maybe) but it may not be needed in your case
  • If you use this same example, you can add a few other event to make the process a little cleaner. Since the website field is on the form, you know that if the website is blank then there’s no need to even show the Tab at all. I would add scripts to these events:
    • OnLoad of the form– If the website is empty then set the visibility on the tab to false
    • OnChange of the website field – If the website is set then show the Tab, if it’s cleared out then hide the Tab

Understanding the Microsoft Dynamics CRM Performance Center

Note: I originally posted this at cobalt.net

The Microsoft Dynamics CRM Performance Center is a fantastic addition to CRM which can help you troubleshoot performance issue related to loading forms in CRM. I’ve found a few online references about the CRM Performance Center but they all focus on how to access it and don’t really give you context for interpreting the results. This is my attempt to combine the diagnostics messages with other CRM materials (Microsoft Dynamics CRM 2013 Updated Form Performance, http://blogs.msdn.com/b/crm/archive/2013/10/31/microsoft-dynamics-crm-2013-updated-form-performance.aspx) in order to make the Performance Center more helpful for the CRM community.

Starting the Performance Center

The Performance Center is available in CRM Online and CRM OnPremise 2013 SP1 or higher. The performance center doesn’t seem to work in Chrome (the browser closes with the key combination), but IE 8+ works fine.

To enable the Performance Center:

  1. Open a form that you want to benchmark
  2. Hit Control+Shift+Q to open the Performance Center window
  3. Click ‘Enable’ to start logging, and then ‘Close’

performance center 1

  1. Refresh the form and open the performance center again
  2. Verify the benchmarks are now loaded
  3. Click ‘Select Major’ to get a summary of milestone.

performance center 2

  1. When you’re done with the Performance Center, make sure to click ‘Disable’ to stop the logging, so you aren’t adding additional overhead.

Diagnostic Messages and Associated Events

Diagnostics Message: Form Load Start (→ 0ms)

  1. The diagnostics timer starts and form initialization begins
  2. The form load bootup process starts, which requests entity instance data, configuration information, CSS, and Javascript tags from the CRM server.
  3. Entity metadata and the form retrieval – The layout is retrieved from the browser cache
  4. Data binding and building the read ready form – The form layout and record data from the previous two steps are built and displayed to the user. All of the fields and their data are visible but they aren’t editable yet. This state is called View Ready, or Read Ready.

Diagnostic Message: Read-Ready (→ 931 ms)

  1. Transitioning the form to edit ready – The form downloads any additional Javascript which has logic for any controls on the form. The Javascript is executed in order. Individual field controls are initialized.
  2. Social pane and Inline subgrids initialization – In this stage, data is pulled from related records for display in the Social pane or subgrids on the form.
    • Expanded grids in the current viewing area are loaded
      Diagnostic Message:  Initialize Controls – ViewportInlineEditControlInitializer (→ 2452 ms)
    • Expanded grids off the current viewing area are loaded
      Diagnostic Message:  Initialize Controls – NonViewportFormBodyInlineEditInitializer (→ 2567 ms)
    • Collapsed grids are loaded
      Diagnostic Message:  Initialize Controls – DeferredQuickFormInlineEditInitializer (→ 2778 ms)
    • Load the Social Wall
  3. The Form’s OnLoad event is executed

Diagnostic Message:  Form Full Controls Init (→ 3390 ms)

At this stage, the form is completely editable. Clearly there are a lot of moving parts when it comes to rending a single form in Dynamics CRM.

How to Improve Performance

The messages can be a bit misleading because a lot of the events are handled, at least partially, asynchronously. For instance, grids can begin to load in step 6.a, but there’s another event “CompleteInlineEditInitialization” that runs parallel with loading the social wall in 6.d. I think the general approach should be to minimize that critical path of code that must run synchronously.

Before getting into specifics improvements, one easy way to help load time is to simplify what’s available on the form. CRM can be such a powerful tool that sometimes we might get carried away and try to just show everything possible on each form, at the expense of performance and really, user experience. If you’re judicious about what you’re showing then every step could be quicker.

Between initialization and read-ready
The two primary actions here are retrieving the record from the database, and merging that with the HTML template for the form. The big gain you can get here is just from reducing the number of fields that need to be handled. If you have a plugin registered on the Retrieve event of the entity, that time would be logged here, so you may want to look at optimizing you plugin step as well.

Between read-ready and Initialize Controls – ViewportInlineEditControlInitializer
The two big actions here are downloading and running field Javascript and loading expanded grids in the current viewing area.

To reduce time associated with loading and executing Javascript, you can follow a number of best practices described in the article Write code for Microsoft Dynamics CRM forms, available at http://msdn.microsoft.com/en-us/library/gg328261.aspx . Best practices include:

  • Avoid including unnecessary JavaScript web resource libraries
  • Avoid loading all scripts in the Onload event
  • Use collapsed tabs to defer loading web resources

I can’t find any firm references online, but from talking with other CRM developers the consensus is that collapsed Subgrids load more asynchronously than expanded Subgrids. Since they’re collapsed, the form only has the header to render because they records aren’t needed until the grid is expanded.  Based on the diagnostics messages, it seems like the most intensive grids to load are:

  1. Expanded grids in the current view
  2. Expanded grid outside the current view
  3. Collapsed grids

If you’re seeing large times in this area, you may want to look at changing grids to be collapsed, or at least lower down the page. Either way, you should see a reduction in the critical path to loading a page.

Another approach here is to limit the columns that are displayed in the grids (not just the count, but the logical location of the records). If you’re on an Account record looking at the names of associated Contacts, you’re touching one table for the contact info. If the contact grid also includes address information, now you’re linking to both the contact and customeraddress table and your query will take longer to execute.

Between Initialize Controls – ViewportInlineEditControlInitializer and Initialize Controls – NonViewportFormBodyInlineEditInitializer
It seems like most of the time in this section is for loading expanded grids off the current viewing area. As I mentioned before, these can either be collapsed or removed completely to speed up load time.

Between Initialize Controls – NonViewportFormBodyInlineEditInitializer and Initialize Controls – DeferredQuickFormInlineEditInitializer
Since the times here are for initializing collapsed grids, there’s not much you can do to speed up this stage besides removing the Subgrids altogether.

Between Initialize Controls – DeferredQuickFormInlineEditInitializer and Form Full Controls Init
The form Social Wall is loaded and the forms OnLoad event is executed. If you’re seeing excessive slowness here you can try to limit what’s on the Wall or remove it altogether, or dig into your event code to look for inefficiencies in either the script logic or even what’s loaded (see Write code for Microsoft Dynamics CRM forms above).

Conclusion

Microsoft Dynamics CRM is an incredibly extensible and customizable tool, but with that freedom comes a potential for performance issues. By removing unnecessary form fields and optimizing Subgrids, we’re able to speed up performance and give a cleaner, crisper user experience. Although there will always be some minimum load time for forms, if we’re selective about what we present and how it’s presented, we can greatly enhance the user’s experience and increase overall satisfaction.