This project is read-only.

How to develop your own tool

Create a project

First, create a new Visual Studio project of type library

image

 

Update project properties

Project properties are used to display your tool in the tools list. Title, Description and Company are used.

image

 

Add references

Add the following references to the project:

  • Microsoft.Crm.Sdk.Proxy
  • Microsoft.Xrm.Sdk
  • System.Drawning
  • System.Runtime.Serialization
  • System.ServiceModel
  • System.Windows.Forms
  • XrmToolBox (this tool executable)

References should look like the screenshot below

image

 

Add a user control

Add a new user control

image

This user control must implement the IMsCrmToolsPluginUserControl interface defined in the XrmToolBox executable.  The easiest way to do this is to inherit from the XrmToolBox.PluginBase. The interface contains the following elements:

using System;
using System.Drawing;
using Microsoft.Xrm.Sdk;

namespace XrmToolBox
{
    public interface IMsCrmToolsPluginUserControl
    {
        /// <summary>
        /// Gets the organization service used by the tool
        /// </summary>
        IOrganizationService Service { get; }

        /// <summary>
        /// Gets the logo to display in the tools list
        /// </summary>
        Image PluginLogo { get; }

        /// <summary>
        /// EventHandler to request a connection to an organization
        /// </summary>
        event EventHandler OnRequestConnection;

        /// <summary>
        /// EventHandler to close the current tool
        /// </summary>
        event EventHandler OnCloseTool;

        /// <summary>
        /// Method to allow plugin to Cancel a closing event, or perform any save events required before closing.
        /// </summary>
        void ClosingPlugin(PluginCloseInfo info);

        /// <summary>
        /// Updates the organization service used by the tool
/// </summary> /// <param name="newService">Organization service</param> /// <param name="actionName">Action that requested a service update</param> /// <param name="parameter">Parameter passed when requesting a service update</param> void UpdateConnection(IOrganizationService newService, string actionName = "", object parameter = null); } }

 

Implement the interface on the user control

You may choose to “roll your own”, but the simplest way to get started is to use the PluginBase. It fully implements the interface, and allows you to focus completely on your plug-in logic.

 

Plug-in Entry and Exit Methods

You can choose to trigger any specific plug-in logic however you like.  In this tutorial, we’ll use a button, “BtnWhoAmI” to start the logic of the plug-in, and “BtnClose” to close the plug-in.  Add these two buttons to your plug-in using the design window.  After they are added double click them to generate the Click event handlers.  Implement them as follows:

private void BtnWhoAmI_Click(object sender, EventArgs e)
{
    ExecuteMethod(ProcessWhoAmI);
}
 
private void BtnClose_Click(object sender, EventArgs e)
{
    base.CloseTool();
}

 

The CloseTool will call an event in the XrmToolBox that will then call the ClosingPlugin method (ClosingPlugin will get called anytime a plug-in has to close).

public virtual void ClosingPlugin(PluginCloseInfo info)
{
    if (info.FormReason != CloseReason.None ||
        info.ToolBoxReason == ToolBoxCloseReason.CloseAll ||
        info.ToolBoxReason == ToolBoxCloseReason.CloseAllExceptActive)
    {
        return;
    }

    info.Cancel = MessageBox.Show(@"Are you sure you want to close this tab?", @"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes;
}

Its uses the standard Windows Form Cancel Event to cancel the close by setting Cancel to true.  The PluginBase by default will pop up a MessageBox with a standard, “Are you sure” message, whenever the user attempts to close a single plug-in.  If the user selects to close multiple tabs, or closes the form itself, it won't prompt the user.  If there are config settings that need to be saved in the plug-in, this method should be overriden, most likely calling any custom plug-in closing logic required, then calling base.ClosingPlugin. 

 

The ExecuteMethod handles ensuring that the XrmToolBox has a valid open connection, before attempting to make an SDK call.  If it doesn’t have a valid connection, it will prompt the user to connect, and then call the method passed in, in this case “ProcessWhoAmI”.

 

Plug-in Logic

In order to simplify multithreading logic, the base provides a “WorkAsync” method with two signatures different signatures.  One provides the ability to perform multiple actions, and notify the user of the work that is being performed:

WorkAsync("Message To Display...",
    (w, e) => // Work To Do Asynchronously
    {
        w.ReportProgress(0, "Doing Something");
        //Do something
        w.ReportProgress(50, "Doing Something Else");
        //Do something else
 
        // Populate whatever the results that need to be returned to the Results Property
        e.Result = new object();
        w.ReportProgress(99, "Finishing");
    },
    e => // Finished Async Call.  Cleanup
    {
        // Handle e.Result
    },
    e => // Logic wants to display an update.  This gets called when ReportProgress Gets Called
    {
        SetWorkingMessage(e.UserState.ToString());
    }
);

 

The other, which we will use for this tutorial, assumes that one SDK call is being performed and and provides actions to perform the call, and process the result:

WorkAsync("Retrieving your user id...",
    (e) => // Work To Do Asynchronously
    {
        var request = new WhoAmIRequest();
        var response = (WhoAmIResponse)Service.Execute(request);
 
        e.Result = response.UserId;
    },
    e =>  // Cleanup when work has completed
    {
        MessageBox.Show(string.Format("You are {0}", (Guid)e.Result));
    }
);

 

It is very important to note that any time you access the Service property, your call hierarchy should always go through the ExecuteMethod, and WorkAsync method!

 

Optional – Add a Logo

By default the PluginBase will return null for the plug-in logo, which results in no logo being displayed.  To add your own logo, first add an image to your project resources:

Project Properties –> Resources –> Add Resource –> Add Existing File, and select the image you’d like to use. The image must be square, with 80 pixels on each side.

Then override the PluginLogo Property to return your image:

/// <summary>
/// Gets the logo to display in the tools list
/// </summary>
public override Image PluginLogo
{
     get { return Resources.MyLogo; }
}

 

Final Complete Class

The final code for our sample tool is the following:

public partial class SampleTool : XrmToolBox.PluginBase
{
    private void ProcessWhoAmI()
    {
        WorkAsync("Retrieving your user id...",
            (e) => // Work To Do Asynchronously
            {
                var request = new WhoAmIRequest();
                var response = (WhoAmIResponse)Service.Execute(request);

                e.Result = response.UserId;
            },
            e =>  // Cleanup when work has completed
            {
                MessageBox.Show(string.Format("You are {0}", (Guid)e.Result));
            }
        );
    }

    #region Events

    private void BtnWhoAmI_Click(object sender, EventArgs e)
    {
        ExecuteMethod(ProcessWhoAmI);
    }

    private void BtnClose_Click(object sender, EventArgs e)
    {
        base.CloseTool();
    }

    #endregion // Events
}

 

Use your tool

Finally, compile the project and move the resulting assembly into the same folder as the XrmToolBox executable

Last edited Dec 8, 2014 at 3:35 PM by hulk2484, version 10

Comments

tanguy92 Dec 3, 2014 at 2:13 PM 
Writing documentation for each individual tool would be a huge amount of work. But if you have time to write documentation, then I would be happy to include it in this documentation section

sbespalov Oct 4, 2013 at 3:57 PM 
It was a great idea to combine the tools. It would be very helpful if the documentation on each individual tool component were brought into the Toolbox pages or referenced as hyperlinks to the individual tool components pages.
Thanks.
Sergei