Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / productivity / Office / Office-Automation

Creating a Visio Add-In in VS2017

5.00/5 (3 votes)
4 Mar 2018CPOL5 min read 11.7K  
How to create a Visio Add-in in VS2017

Problem Statement

A good friend asked me the following question:

How can I in Visio change the color to a previously selected color just by selecting a shape?

Sounds simple enough, but there are some caveats, so here is my attempt to tackle this problem. The main caveats were:

  • hooking up the SelectionChanged event
  • keeping and accessing the state in the Ribbon (for the default color)
  • setting the color of the selected shape

The code for this project can be found here.

Visio Add-In – Preparation

I decided to use Visual Studio 2017 to create a Visio Add-In. To do this, we need to install the “Office/SharePoint development” workload. Since Visual Studio 2017; the installer allows for modular installation, so we just need to add this to our installation.

Start Visual Studio Installer (Start -> type “Visual Studio Installer”). In the installer window, select “More > Modify”:

image

After a little while, this takes us to the workloads selection screen. Select Office/SharePoint development and then click “Modify”.

image

When you launch Visual Studio again, you’ll find a new bunch of project templates.

Creating the Visio Add-in

In VS, create a new project (File > New > Project…) like this:

image

As you can see, there are new project templates for “Office/SharePoint”. I choose the Visio Add-in project and gave it an appropriate name “ActOnShapeSelection”.

The result is a project with one C# file (ThisAddIn.cs). This is where we will initialize our events. As a test, we show a message box when starting our add-in, and another one when closing it:

C#
public partial class ThisAddIn
{
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        MessageBox.Show("Startup ActOnShapeSelection");
    }

    private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
    {
        MessageBox.Show("Shutdown ActOnShapeSelection");
    }

    //
}

Remark: By default, the namespace System.Windows.Forms is not included in the using list, so we will need to add it. An easy way to do this is by clicking on the red-underlined MessageBox and typing ctrl+; (control + semicolon that is). Now we can choose how to solve the “using problem”.

Starting the application (F5) will now start Visio and our first message box is indeed shown. Closing Visio shows the second message box. No rocket science so far, but this proves that our add-in is loaded properly into Visio.

Convincing Visio to do something when a shape is selected is just a bit harder.

Wiring the Selected Event

C#
public partial class ThisAddIn
{
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        Application.SelectionChanged += Application_SelectionChanged;
    }

    private void Application_SelectionChanged(Visio.Window Window)
    {
        MessageBox.Show("SelectionChanged ActOnShapeSelection");
    }
//
}

The SelectionChanged event must be wired in the startup event. Later, we will do the same for the ShapeAdded event. Once you know this “trick”, things become easy.

When running this code, each time we select something in Visio, we see our fancy message box. So the event wiring works. Now we want to be able to only execute code when a shape is selected. Let’s investigate if we can find out something about the selected object(s) in the “Window” parameter:

image

As expected, this is a dynamic object. Visio is accessed over COM. Luckily, the debugger allows to expand the dynamic view members. Looking through the members of this object, we find a property “Selection”. This looks promising! Looking a bit further, “Selection” is an implementation of the interface IVSelection. And this interface inherits from IEnumerable.

So Selection is actually an enumerable collection of all the selected items, hence it can be handled using a standard foreach( ). Let’s try this:

C#
private void Application_SelectionChanged(Visio.Window Window)
{
    //MessageBox.Show("SelectionChanged ActOnShapeSelection");
    Visio.Selection selection = Window.Selection;
    foreach (dynamic item in selection)
    {
        Visio.Shape shp = item as Visio.Shape;
        if (shp != null)
        {
            shp.Characters.Text = "selected";
        }
    }
}

We run the add-in again (F5) and add 2 shapes on the page. When we select the shapes, they get the text “selected”. So now we are capable of knowing which shapes are selected and doing something useful with them. Let’s add a new ribbon with actions to perform on our shapes. After all, that is the purpose of this exercise.

Adding a Ribbon

This can easily be done by right-clicking on the project, New Item. Then select Office/SharePoint > Ribbon (Visual Designer).

image

Name this ribbon “ActionsRibbon.”

Opening the ribbon, we can now use the visual designer. Make sure that the toolbox window is visible (View > Toolbox).

Now we add 3 ToggleButtons on the design surface, named btnRed, btnGreen, and you guessed it: btnBlue. For each of the buttons, we add a Click event by double-clicking on the button. Using the GroupView Tasks, we also add a DialogBoxLauncher. This will open a ColorDialog for selecting a custom color.

image

Double-click the group to implement the “DialogLauncherClick” event, which will handle this.

The ActionsRibbon will contain its own data, being the 3 components for a color (Red, Green, Blue):

C#
public byte Red { get; private set; }
public byte Green { get; private set; }
public byte Blue { get; private set; }

Each of the toggle buttons will toggle its own color component:

C#
private void btnRed_Click(object sender, RibbonControlEventArgs e)
{
    Red = (byte)(255 - Red);
}

private void btnGreen_Click(object sender, RibbonControlEventArgs e)
{
    Green = (byte)(255 - Green);
}

private void btnBlue_Click(object sender, RibbonControlEventArgs e)
{
    Blue = (byte)(255 - Blue);
}

Remark: This code works fine if there is no possibility for a custom color. When selecting a custom color, the values will become something other than 0 or 255 and not correspond to the UI anymore. I leave it as an exercise to the reader to make a better implementation.

Choosing a custom color:

C#
private void group1_DialogLauncherClick(object sender, RibbonControlEventArgs e)
{
    ColorDialog dlg = new ColorDialog { Color = Color.FromArgb(Red, Green, Blue) };

    if (dlg.ShowDialog() == DialogResult.OK)
    {
        Red = dlg.Color.R;
        Green = dlg.Color.G;
        Blue = dlg.Color.B;
    }
}

In the SelectionChanged event of our AddIn class, we now need to refer to the RGB values from the Ribbon. Here is the full code for the event handler:

C#
private void Application_SelectionChanged(Visio.Window Window)
{
    ActionsRibbon rib = Globals.Ribbons.ActionsRibbon;
    Visio.Selection selection = Window.Selection;
    foreach (dynamic item in selection)
    {
        Visio.Shape shp = item as Visio.Shape;
        if (shp != null)
        {
            shp.Characters.Text = "selected";
            shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionObject,3, 0].FormulaU = 
                                           $"THEMEGUARD(RGB({rib.Red}, {rib.Green}, {rib.Blue}))";
        }
    }
}

There is some Visio-fu to set the color. Consider this as a cookbook recipe. When you do this, you’ll get the desired result. Visio is not always straightforward, one could say.

Now we have a working Visio add-in, that does what was asked. BUT when we add a new shape, it will automatically receive the selected color. To solve this, we add another event handler:

C#
Application.ShapeAdded += Application_ShapeAdded;

We also add a boolean indicating if we are adding a shape or not.

C#
bool _isAddingAShape = false;

In the ShapeAdded event, we set its value to true:

C#
private void Application_ShapeAdded(Visio.Shape Shape)
{
    _isAddingAShape = true;
}

And we modify the SelectionChanged event to do nothing when a shape was added. This event will be called when a shape is selected, AND when a shape is added (which indeed selects it). The code:

C#
private void Application_SelectionChanged(Visio.Window Window)
{
    if (! _isAddingAShape)
    {
        ActionsRibbon rib = Globals.Ribbons.ActionsRibbon;
        Visio.Selection selection = Window.Selection;
        foreach (dynamic item in selection)
        {
            Visio.Shape shp = item as Visio.Shape;
            if (shp != null)
            {
                shp.Characters.Text = "selected";
                shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionObject, 3, 0].FormulaU = 
                                    $"THEMEGUARD(RGB({rib.Red}, {rib.Green}, {rib.Blue}))";
            }
        }
    }
    _isAddingAShape = false;
}

Conclusion

Using Visual Studio, it took us about 100 lines of code to implement the desired behavior. It would not be hard to add more actions to the ribbon. But in that case, it will be wise to move the code to perform the action into the ActionRibbon class instead of using the values of this class in the AddIn class.

The hardest part was to find how to obtain the newly created Ribbon from within the AddIn class. All the rest is just a straightforward implementation.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)