How to: Use Managed Code to Add a Custom Command to the Ribbon

Applies to: Office 2010 | Project 2010 | Project Server 2010 | SharePoint Server 2010

This article shows how to programmatically add a custom tab and a command to the Fluent user interface (the ribbon) in Microsoft Project 2010, by using a managed code add-in that is developed with Microsoft Office development tools in Microsoft Visual Studio 2010. The custom button calls a method in the add-in that toggles the Task Name cell color of manually scheduled tasks. This article enables you to compare the Microsoft Visual Basic and Microsoft Visual C# code in a simple solution that modifies the Project 2010 ribbon.

The RibbonAddIn solution in this article does the same job as the macro that is described in How to: Use VBA to Add a Custom Command to the Ribbon. The add-in code can be directly compared with the Microsoft Visual Basic for Applications (VBA) code in that article. The managed code Microsoft.Office.Interop.MSProject library for Project 2010 duplicates the objects and members in the MSProject library in VBA. There are many advantages to using a managed code add-in instead of a VBA macro, some of which are described in the introductory section of Walkthrough: Building a Managed Code Add-in to Check PWA Compatibility. A big advantage in Visual Studio 2010, compared to previous versions, is that you can use named parameters and optional parameters in Visual C# just as you can in Visual Basic.

The Ribbon Designer in Visual Studio provides an advantage in modifying the Project 2010 ribbon because it enables you to drag common ribbon elements from the Toolbox to a design view, instead of using XML. You can also use XML to modify the ribbon, and it is much easier to edit XML in Visual Studio than it is in VBA. For more information, see Ribbon Overview.

An add-in is easily deployed by using ClickOnce to save the installation files to a central repository. The developer can specify how often the add-in checks the repository for updates. Installation can also automatically check for and install prerequisite components.

Procedure 1. To create an add-in project for the ribbon

  1. Run Visual Studio 2010 as an administrator, and then create a Project 2010 Add-in project. For example, name the project RibbonAddIn. Figure 1 shows creation of the project with the Visual Basic template. You can also use Visual C#.

    Figure 1. Creating a Project 2010 add-in with the Visual Basic template

    Creating a Project 2010 add-in for Visual Basic

  2. In the drop-down menu at the top of the New Project dialog box, select .NET Framework 3.5. Clear the Create directory for solution check box, and then click OK.

Visual Studio creates the RibbonAddIn project with the ThisAddIn.vb (or ThisAddIn.cs) file, which includes the ThisAddIn_Startup and ThisAddIn_Shutdown event handlers. For a simple ribbon control that does not involve application-level events or document-level events, the startup and shutdown event handlers do not need changes. Procedure 2 shows how to add a Visual Designer component for the ribbon.

Procedure 2. To modify the ribbon by using the Visual Designer

  1. In Solution Explorer, right-click the RibbonAddIn project, and then add a new item. In the Add New Item dialog box, click Ribbon (Visual Designer). For example, name the class ManualTaskColor.

  2. In the Toolbox, expand the Office Ribbon Controls tab, and then drag a Tab control to the ManualTaskColor ribbon in the Design view.

    Note

    If you use the TabAddIns (Built-In) tab in the Design view, the ribbon controls that you add will appear in the Add-Ins tab in the Project 2010 ribbon.

    To add a group or control to an existing tab, click the TabAddIns (Built-In) tab in the Design view, expand the ControlId property, and then change the OfficeId property to the tab name. For example, to use the View tab, change the OfficeId property to TabView. To download a list of ribbon control IDs for built-in controls, see Office 2010 Help Files: Office Fluent User Interface Control Identifiers.

  3. Select the tab1 control in the design view, and then open the Properties pane. For example, name the tab tabHighlight, which also becomes the ControlId property name. Change the Label property to Highlight.

  4. Drag a Group control from the Toolbox to the Highlight tab in the Design view. In the Properties pane for the group1 control, for example, change the name of the group to rGroupManualTask, and change the Label property to Highlight.

  5. Drag a ToggleButton control (or you can use a Button control) from the Toolbox to the Highlight group in the Design view.

  6. Select the toggleButton1 control in the Design view, and change the following properties:

    1. Change the (Name) property to tBtnManualTaskColor.

    2. Change the Checked property to True. When the add-in runs, the state of the toggle button is on (that is, the button is highlighted in the ribbon).

    3. Change the Label property to Toggle Manual Task Color.

    4. To show the same image that the VBA example shows, type DiagramTargetInsertClassic for the OfficeImageId property.

Figure 2 shows the Design view for the ribbon with the completed Highlight tab, Highlight group, and Toggle Manual Task Color button.

Figure 2. Using the Design view to modify the Project 2010 ribbon

Using the ribbon Design view in Visual Studio

Visual Studio shows a generic icon for the button when you specify the OfficeImageId property. Instead of using a built-in icon, you can create an image and use it for the Image property. Many icons are also available in the 2007 Office System Add-In: Icons Gallery and in the Office 2010 Add-In: Icons Gallery.

For more information about using Visual Studio 2010 to modify the user interface of Microsoft Office applications, see Office UI Customization.

Tip

As shown in How to: Use VBA to Add a Custom Command to the Ribbon, you can find a valid value for the OfficeImageId property by temporarily modifying the ribbon in the Project Options dialog box:

  1. In Project 2010, click the Customize Ribbon tab of the Project Options dialog box.

  2. Add a button to one of the existing groups on the ribbon, and then set the icon for the command from the selection of available icons.

  3. To export the ribbon modification to the ProjectCustomizations.exportedUI file, click Import/Export, and then click Export all customizations. The icon name is the value of the imageMso attribute of the mso:button element.

Procedure 3 shows how to create the button Click event handler and the code that runs when you click the Toggle Manual Task Color button.

Procedure 3. To create the code for the button Click event

  1. In the ribbon Design view, click the Toggle Manual Task Color button to select it. In the Properties pane, click the Events icon to see the events that are available for the ribbon control (the ToggleButton control has only the Click event).

  2. In the Properties pane, double-click the Click event to create the tBtnManualTaskColor_Click event handler. Visual Studio opens the ManualTaskColor.vb file (or the ManualTaskColor.cs file) at the event handler code.

  3. Add namespace references and options to the ManualTaskColor code file, as follows:

    Option Explicit On
    
    Imports Microsoft.Office.Tools.Ribbon
    Imports MSProject = Microsoft.Office.Interop.MSProject
    
    using System;
    using Microsoft.Office.Tools.Ribbon;
    using MSProject = Microsoft.Office.Interop.MSProject;
    
  4. Add the ManualTaskColor class constants and variables. The app object can be instantiated in the ManualTaskColor_Load event handler, which is called when Project starts to run. The Globals class provides access to the Application object for the add-in.

    Public Class ManualTaskColor
    
        Private Const WHITE As Integer = &HFFFFFF
        Private Const LIGHT_BLUE As Integer = &HF0D9C6
    
        Dim app As MSProject.Application
        Dim project As MSProject.Project
    
        Private Sub ManualTaskColor_Load(ByVal sender As System.Object,
                        ByVal e As RibbonUIEventArgs) _
                        Handles MyBase.Load
            app = Globals.ThisAddIn.Application
        End Sub
        ' . . .
    
    namespace RibbonAddIn
    {
        public partial class ManualTaskColor
        {
            private const int WHITE = 0xFFFFFF;
            private const int LIGHT_BLUE = 0xF0D9C6;
    
            MSProject.Application app;
            MSProject.Project project;
    
            private void ManualTaskColor_Load(object sender, 
                RibbonUIEventArgs e)
            {
                app = Globals.ThisAddIn.Application;
            }
            // . . .
    

    The constants are 24-bit colors that can be specified by hexadecimal values. Project 2010 includes methods such as Font32Ex where colors are specified by RGB values.

    Note

    Hexadecimal colors in Project 2010 are expressed in the order B-G-R. For example, &HFF0000 (or 0xFF0000 in Visual C#) is pure blue. You can use the decimal equivalent; for example, 15784390 is the same light blue value as &HF0D9C6, but it is easier to determine the color when using hexadecimal values.

  5. Create the ToggleManualTasksColor method, and call the method from the button Click event handler. The project object can be initialized only after a project is opened and activated, which occurs after the add-in is loaded. If you try to initialize project in the ManualTaskColor_Load event handler, the add-in gives an exception because there is no active project yet.

    Private Sub tBtnManualTaskColor_Click(ByVal sender As System.Object, _
                    ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) _
                    Handles tBtnManualTaskColor.Click
        ToggleManualTasksColor()
    End Sub
    
    Sub ToggleManualTasksColor()
        Dim column As String = "Name"
        Dim rowRelative As Boolean = False
        Dim rgbColor As Integer
    
        project = app.ActiveProject
    
        For Each t As MSProject.Task In project.Tasks
            If (Not t Is Nothing) And (Not t.Summary) Then
                app.SelectTaskField(t.ID, column, rowRelative)
                rgbColor = app.ActiveCell.CellColorEx
    
                If (t.Manual) Then
                    ' Check whether the manual task color is white.
                    If (rgbColor = WHITE) Then
                        ' Change the background to light blue.
                        app.Font32Ex(CellColor:=LIGHT_BLUE)
                    Else
                        ' Change the background to white.
                        app.Font32Ex(CellColor:=WHITE)
                    End If
                Else
                    ' The task is automatically scheduled, 
                    ' so change the background to white.
                    app.Font32Ex(CellColor:=WHITE)
                End If
            End If
        Next
    End Sub
    
    private void tBtnManualTaskColor_Click(object sender, 
        RibbonControlEventArgs e)
    {
        ToggleManualTasksColor();
    }
    
    private void ToggleManualTasksColor()
    {
        string column = "Name";
        bool rowRelative = false;
        int rgbColor;
    
        project = app.ActiveProject;
    
        foreach (MSProject.Task t in project.Tasks)
        {
            if ((t != null) && !(bool)t.Summary)
            {
                app.SelectTaskField(t.ID, column, rowRelative);
                rgbColor = app.ActiveCell.CellColorEx;
    
                if ((bool)t.Manual)
                {
                    // Check whether the manual task color is white.
                    if (rgbColor == WHITE)
                    {
                        // Change the background to light blue.
                        app.Font32Ex(CellColor:LIGHT_BLUE); 
                    }
                    else
                    {
                        // Change the background to white.
                        app.Font32Ex(CellColor:WHITE); 
                    }
                }
                else
                {
                    // The task is automatically scheduled, 
                    // so change the background to white.
                    app.Font32Ex(CellColor:WHITE); 
                }
            }
        }
    }
    
  6. To test and debug the add-in within Visual Studio, press F5. For example, add some tasks to the project, select the Highlight tab in the ribbon, and then click Toggle Manual Task Color twice (Figure 3). If you set a breakpoint on the statement that sets rgbColor, the debugger shows that app.ActiveCell.CellColorEx = 16777215 for a task that has a white background color.

    Note

    If the Project application is open, close it before you run the add-in within Visual Studio. Visual Studio creates a temporary strong name key file to sign the assembly, and then starts the Project application with the add-in.

    If your Global.mpt file or a .mpp file that you open has the Project_Open event handler or the Project_Activate event handler described in How to: Use VBA to Add a Custom Command to the Ribbon, comment-out or remove the VBA event handler before running the ManualTaskColor add-in.

The rgbColor variable is declared as type Integer, which in the Microsoft .NET Framework can hold up to a 32-bit value. In VBA, rgbColor must be declared as type Long. For a table that compares VBA and .NET Framework types, see Tables of VBA Object Model Changes.

Some properties, such as the Manual property and the Summary property of a Task, are declared as type Object in the Microsoft.Office.Interop.MSProject library. In Visual C#, you must cast those properties to the specific type. In Visual Basic, the cast is not necessary. For example, the If (t.Manual) statement in Visual Basic must be if ((bool)t.Manual)in Visual C#. You can use Microsoft Intellisense or the Object Browser in Visual Studio to find which properties are of type Object.

Visual Studio 2010 enables you to use optional parameters and named parameters in Visual C#, in the same way as Visual Basic. For example, even though the SelectTaskField method has six optional parameters, the Visual Basic statement app.SelectTaskField(t.ID, column, rowRelative) can be expressed the same way as it is in Visual C# (with a semicolon for the statement end). The Font32Ex method has ten parameters. You can specify the eighth parameter, for example, by using the app.Font32Ex(CellColor:=LIGHT_BLUE) statement in Visual Basic. In Visual C#, you can use the app.Font32Ex(CellColor:LIGHT_BLUE); statement.

Figure 3 shows that the ManualTaskColor add-in works the same way as the ToggleManualTasksColor VBA macro described in How to: Use VBA to Add a Custom Command to the Ribbon.

Figure 3. Using the ManualTaskColor add-in

Using the custom ribbon command

When the add-in works correctly, you can use Procedure 4 to publish the add-in so that others can easily install it.

Procedure 4. To publish the ManualTaskColor add-in

  1. In Solution Explorer, right-click the RibbonAddIn project, and then click Properties.

  2. In the RibbonAddIn tab, click the Signing tab, and then ensure that the Sign the assembly check box is selected.

  3. Use the Choose a strong name key file drop-down list to create a new key file. For example, create RibbonAddIn.snk. You can choose whether to protect the key file with a password. You can delete the temporary strong name key file that Visual Studio created during testing.

  4. Click the Publish tab, and examine the Publish Location and the Install Settings options. By default, the add-in is published to the publish\ subdirectory of the Visual Studio project directory. For example, if the project is in C:\VSTO_Projects\RibbonAddIn, the publish directory is C:\VSTO_Projects\RibbonAddIn\publish. You can also publish to a file share, to the URL of a SharePoint document list, or to another website or an ftp server.

    Click Prerequisites to see which prerequisite components the setup program checks for and installs. By default, the setup program checks for the .NET Framework 3.5 SP1 and Windows Installer 3.1 and, if necessary, downloads them from the Microsoft download center.

    Click Updates to specify when the add-in checks for updates. By default, the add-in checks the publication location every seven days. If there is a newer version, the add-in notifies the user to do an update.

  5. Click Publish Now. Run setup.exe on another computer that has Project 2010 installed to test the published add-in.

For deploying a Project 2010 customization, publishing an add-in by using ClickOnce is a much better solution than copying VBA macros to the Global.mpt file on other computers.

Example

Following is the complete code in the ManualTaskColor.vb file for the Visual Basic solution and the ManualTaskColor.cs file for the Visual C# solution.

Option Explicit On

Imports Microsoft.Office.Tools.Ribbon
Imports MSProject = Microsoft.Office.Interop.MSProject

' Toggle the background color of the Name cell of manually scheduled tasks.
' If a manually scheduled task is changed to automatically 
' scheduled, change the Name cell background color to white.
Public Class ManualTaskColor

    Private Const WHITE As Integer = &HFFFFFF
    Private Const LIGHT_BLUE As Integer = &HF0D9C6

    Dim app As MSProject.Application
    Dim project As MSProject.Project

    Private Sub ManualTaskColor_Load(ByVal sender As System.Object,
                    ByVal e As RibbonUIEventArgs) _
                    Handles MyBase.Load
        app = Globals.ThisAddIn.Application
    End Sub

    Private Sub tBtnManualTaskColor_Click(ByVal sender As System.Object, _
                    ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) _
                    Handles tBtnManualTaskColor.Click
        ToggleManualTasksColor()
    End Sub

    Sub ToggleManualTasksColor()
        Dim column As String = "Name"
        Dim rowRelative As Boolean = False
        Dim rgbColor As Integer

        project = app.ActiveProject

        For Each t As MSProject.Task In project.Tasks
            If (Not t Is Nothing) And (Not t.Summary) Then
                app.SelectTaskField(t.ID, column, rowRelative)
                rgbColor = app.ActiveCell.CellColorEx

                If (t.Manual) Then
                    ' Check whether the manual task color is white.
                    If (rgbColor = WHITE) Then
                        ' Change the background to light blue.
                        app.Font32Ex(CellColor:=LIGHT_BLUE)
                    Else
                        ' Change the background to white.
                        app.Font32Ex(CellColor:=WHITE)
                    End If
                Else
                    ' The task is automatically scheduled, 
                    ' so change the background to white.
                    app.Font32Ex(CellColor:=WHITE)
                End If
            End If
        Next
    End Sub
End Class
using System;
using Microsoft.Office.Tools.Ribbon;
using MSProject = Microsoft.Office.Interop.MSProject;

namespace RibbonAddIn
{
    // Toggle the background color of the Name cell of manually scheduled tasks.
    // If a manually scheduled task is changed to automatically 
    // scheduled, change the Name cell background color to white.
    public partial class ManualTaskColor
    {
        private const int WHITE = 0xFFFFFF;
        private const int LIGHT_BLUE = 0xF0D9C6;

        MSProject.Application app;
        MSProject.Project project;

        private void ManualTaskColor_Load(object sender, 
            RibbonUIEventArgs e)
        {
            app = Globals.ThisAddIn.Application;
        }

        private void tBtnManualTaskColor_Click(object sender, 
            RibbonControlEventArgs e)
        {
            ToggleManualTasksColor();
        }

        private void ToggleManualTasksColor()
        {
            project = app.ActiveProject;
            string column = "Name";
            bool rowRelative = false;
            int rgbColor;
            
            foreach (MSProject.Task t in project.Tasks)
            {
                if ((t != null) && !(bool)t.Summary)
                {
                    app.SelectTaskField(t.ID, column, rowRelative);
                    rgbColor = app.ActiveCell.CellColorEx;

                    if ((bool)t.Manual)
                    {
                        // Check whether the manual task color is white.
                        if (rgbColor == WHITE)
                        {
                            // Change the background to light blue.
                            app.Font32Ex(CellColor:LIGHT_BLUE); 
                        }
                        else
                        {
                            // Change the background to white.
                            app.Font32Ex(CellColor:WHITE); 
                        }
                    }
                    else
                    {
                        // The task is automatically scheduled, 
                        // so change the background to white.
                        app.Font32Ex(CellColor:WHITE); 
                    }
                }
            }
        }
    }
}

See Also

Tasks

How to: Use VBA to Add a Custom Command to the Ribbon

Walkthrough: Building a Managed Code Add-in to Check PWA Compatibility

Reference

Tables of VBA Object Model Changes

Other Resources

Office UI Customization

Project Solutions

Ribbon Overview

Office 2010 Help Files: Office Fluent User Interface Control Identifiers

2007 Office System Add-In: Icons Gallery

Office 2010 Add-In: Icons Gallery