Mike Borozdin's Blog

A blog about programming, web and IT in general

Follow Me

Search

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© 2014 Mike Borozdin

Developing Applications for Visio with Visual Studio (VSTO, Windows Forms, WPF, XBAP)

This tutorial demonstrates how to extend the Visio functionality by writing an Visio add-in with VSTO, creating a standalone application with both Windows Forms and WPF, and finally by building a browse application with WPF (XBAP).

Visio is a conventional tool for drawing various diagrams. However, sometimes we are not satisfied with its default functionality and want to extend it. There are thousands of reason why one may want to extend the Visio functionality, starting from creating a code generator that will automatically write code based on a UML diagram or will create a database (it is also possible to do a reverse operation and draw diagrams based on your class hierarchy or database schema) to analysing workflow diagrams or supply chains.

Technically there are three ways of extending the Visio functionality.

  • Visio Add-in
  • Standalone desktop application featuring a Visio control
  • Web application hosting a Visio control

This tutorial covers all three approaches describing their pros and cons.

There are some prerequisites to this tutorial which are:

  • Visual Studio 2010
  • Visio 2010

However, you can try using Visio 2007 and Visual Studio 2008, I just haven’t tested my code for those versions.

In this tutorial we will cover how to write a simply application that just lists all the shapes that are present in a diagram. For this reason we also draw a small diagram that illustrates the process of applying for a bank account and receiving a credit card.

image

Visio Add-In

The first approach of extending the Visio functionality is writing an add-in for it. Visual Studio provides tools for extending Microsoft Office applications that are called VSTO (Visual Studio Tools for Office). However, their set of features for Visio is somewhat limited. The main restriction is inability to embed a user interface in Visio by using panes that are available for Word and Excel add-ins. Of course, it is possible to create our own windows, but having a window over Visio is not the best usability decision, because it already looks as a standalone application and not Visio.

Anyway, in order to create a Visio add-in you have to launch Visio Studio, create a new project and choose Visual C# –> Office –> 2010 –> Visio 2010 Add-in .

image

 

This will generate some dummy code for you. Our next step is adding interaction between our add-in and a user. This can be accomplished by adding a Ribbon to our application. You have to navigate to Project->Add Component->Office->Ribbon (Visual Designer).

image

After adding a Ribbon it’s time to drop some control to it. If you open the Toolbox you will see a list of Ribbon controls.

image

We just need to drop a button that will open a new window which will contain a ListBox for displaying shapes. Having places a button onto the Ribbon you just have to create a new Form (let’s call it FormListShapes) and to insert a ListBox (lstShapes).

Then we go back to the Ribbon and to the newly created button and add a click handler that shows a window.

   1:  private void btnListShapes_Click(object sender, RibbonControlEventArgs e)
   2:  {
   3:      FormListShapes formListShapes = new FormListShapes();
   4:      formListShapes.Show();
   5:  }

Now we switch back to the Form and finally put some code that will display all the present shapes in a diagram.

   1:  using Visio = Microsoft.Office.Interop.Visio;
   2:  //...
   3:  public FormListShapes()
   4:  {
   5:      InitializeComponent();
   6:   
   7:      foreach (Visio.Shape shape in Globals.ThisAddIn.Application.ActivePage.Shapes)
   8:      {
   9:          lstShapes.Items.Add(shape.Text + " (" + shape.Name + ")");
  10:      }
  11:  }

Okay, this piece of code requires a few explanations. We iterate through each shape in a currently open page and display its caption (shape.Text) and a shape type (shape.Name) in parentheses. Please, also pay attention at line 7 that makes use of class Globals that is automatically generated by Visual Studio and is meant to provide access to the Visio object from other parts of the appliation. You can get more information on this class on MSDN.

Please, note that we will cover the Visio API in next tutorials, when we will speak about its object model, advanced diagram analysis, on the fly diagram creation and so on.

Using Visio in Standalone Desktop Applications

Although writing a Visio add-in seems to be an obvious idea when it is necessary to extend its functionality, it is not always the best choice. Firstly, as it is shown above, there are some limitations when it comes to designing a convenient UI. In order to add any control to any other place besides the Ribbon, one has to create separate window that already gives a feeling of having a standalone application rather than a Visio add-in. Secondly, there are cases when you have a sophisticated application that requires a just little bit of interaction with Visio, then it is pretty natural to embed Visio in that application instead of writing an add-in for that.

Fortunately, Visual Studio is capable of handling that task. Moreover, you can use both Windows Forms and WPF. We will start with Windows Forms, but later you will see that embedding Visio in a WPF application is not any harder.

Embedding Visio in a Windows Forms Application

I hope we can easily skip that part that tells how to create a Windows Forms application and we can proceed with adding a Vision control to a newly created form.

Obviously, you won’t find anything related to Visio in the Toolbox. Anyway, you still open the Toolbox, right-click and then select ‘Choose Items’.

image

Switch to the COM Components tab and find Microsoft Office Visio 14.0 Drawing Control.

image

After doing that you will see a new control in the Toolbox, just drag-n-drop to the form you will see something like the following:

image

Unlike a Visio add-in when you can open a diagram and Visio and then run an add-in, if you embed Visio in your application you have to write code in order to open a diagram. It is just sufficient to specify a value of the Src property of a Visio control to open a diagram.

axDrawingControl1.Src = "Some Diagram.vsd";

However, we do no want to hardcode a path to a diagram, instead we will provide a dialog for choosing a Visio diagram to open.

So, just think about the way you want to open the dialog. I just created added a main menu with the ‘Open’ item.

Then, drop an OpenFileDialog onto you form and set its Filter property to ‘Visio Diagrams|*.vsd;*.vdx’, so that users cannot open any other file types.

image

Finally, we can add some code that will open a chosen diagram for us.

   1:  private void openToolStripMenuItem_Click(object sender, EventArgs e)
   2:  {
   3:      if (dlgOpenDiagram.ShowDialog() == System.Windows.Forms.DialogResult.OK)
   4:      {
   5:          axDrawingControl1.Src = dlgOpenDiagram.FileName;
   6:      }
   7:  }

If you compile and run the application now, you will see a form list that (after you open a diagram, of course):

image

Okay, it looks good! So, now we just want to list any shape that is present in a diagram, like we did for a Visio add-in before. Thus, drop a ListBox onto the form.

We will populate that ListBox as soon as you open a diagram. How does the application know if you open a diagram? Obviously, via some kind of event.

There is an event called DocumentOpened that is fired every time a new diagram is opened in a control. The thing we need to do is just to subscribe to that event. So, just add the following code to your form constructor.

   1:  public Form1()
   2:  {
   3:      InitializeComponent();
   4:   
   5:      axDrawingControl1.DocumentOpened += new AxMicrosoft.Office.Interop.VisOcx.EVisOcx_DocumentOpenedEventHandler(axDrawingControl1_DocumentOpened);
   6:  }

If you wonder about the axDrawingControl1_DocumentOpened() method, then it is automatically generated by Visual Studio, if you just press ‘Tab’ twice after typing ‘axDrawingControl1.DocumentOpened’. So, you don’t have to worry about going through a documentation to find a method signature.

Now, you can add code that lists Visio shapes to that event handler.

   1:  private void axDrawingControl1_DocumentOpened(object sender, AxMicrosoft.Office.Interop.VisOcx.EVisOcx_DocumentOpenedEvent e)
   2:  {
   3:      foreach (Visio.Shape shape in axDrawingControl1.Window.Application.ActivePage.Shapes)
   4:      {
   5:          lstShapes.Items.Add(shape.Text + " (" + shape.Name + ")");
   6:      }
   7:  }

The code looks basically similar to the same for a Visio add-in, with the only exception that instead of referencing Globals, you just point to your Visio control and its Window.Application.

As a result after compiling the application you should see something like this.

image

Embedding Visio in a WPF Application

That Visio control that we added into a Windows Forms application is, in fact, an ActiveX control, that might be pretty evident because it is located in the COM Components tab. However, WPF does not support ActiveX controls directly. But there is always a workaround.

You can place a WindowsFormHost control onto your WPF window and that control can host any Windows Forms control. Pretty convenient.

Thus, just add WindowsFormHost to the Toolbox. It is located in the WPF Components tab.

image

And then just place this control onto a form.

   1:  <StackPanel>
   2:      <WindowsFormsHost Name="host" />
   3:  </StackPanel>

Next steps, however, are bit less obvious. We have to add a Visio control, but we can’t just drag-n-drop it, like we did before. Visual Studio WPF designer just does not support ActiveX objects. So, we have to add a control programmatically, but first we have to add all the necessary references.

Go to the Solution Explorer, right-click on ‘References’ and press ‘Add Reference’, then switch to the COM tab and find Microsoft Visio Type Library.

image

This will add a reference to the DLL containing classes related to Visio. However, it doesn’t contain the control itself. So, we have to add yet another reference that can be a bit tricky. Basically, we should look for AxInterop.Microsoft.Office.Interop.VisOcx.dll. There is a tutorial saying to create a separate project for Windows Forms Control Library where you have to drag-n-drop that Visio ActiveX control and then reference that project. It’s one way to go. The other way is just to directly reference that DLL from an old project. Please, note those AxIntertop DLL are automatically created by Visual Studio once you drop a control.

So you can add a reference to a DLL created in the Windows Forms project. So, open the Add Reference open and go to the Browse tab and navigate to the ‘bin/Debug/’ folder of the Windows Forms project and choose AxInterop.Microsoft.Office.Interop.VisOcx.dll.

image

Okay, the preparatory steps are done. We can finally add a Visio control. This time, however, it’s done solely programmatically.

First of all, import the necessary namespaces:

   1:  using AxMicrosoft.Office.Interop.VisOcx;
   2:  using Visio = Microsoft.Office.Interop.Visio;

Then, add a Visio control to the WindowsFormHost:

   1:  public partial class MainWindow : Window
   2:  {
   3:      private AxDrawingControl visioControl = new AxDrawingControl();
   4:   
   5:      public MainWindow()
   6:      {
   7:          InitializeComponent();
   8:   
   9:          this.host.Child = this.visioControl;
  10:      }

We mark the control as a field of our class, so that it can be accessed from its methods.

The next steps are pretty obvious we set a source of a diagram, add event handlers, populate a ListBox, etc. However, it is advisable to set event handlers not in the constructor, but in the Window_Loaded event when the Visio control is known to be fully loaded.

So we set the event of Loaded.

<Window x:Class="VisioWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="650" Width="525" Loaded="Window_Loaded">

And handle it:

   1:  private void Window_Loaded(object sender, RoutedEventArgs e)
   2:  {
   3:      this.visioControl.DocumentOpened += new EVisOcx_DocumentOpenedEventHandler(visioControl_DocumentOpened);
   4:  }

Then, for filling in a ListBox we can use fancy WPF binding:

   1:  private void visioControl_DocumentOpened(object sender, EVisOcx_DocumentOpenedEvent e)
   2:  {
   3:      lstShapes.ItemsSource = this.visioControl.Window.Application.ActivePage.Shapes;
   4:  }
   1:  <ListBox Name="lstShapes">
   2:      <ListBox.ItemTemplate>
   3:          <DataTemplate>
   4:              <StackPanel Orientation="Horizontal">
   5:                  <TextBlock Text="{Binding Path=Text}"/>
   6:                  <TextBlock Text=" ("/>
   7:                  <TextBlock Text="{Binding Path=Name}"/>
   8:                  <TextBlock Text=")"/>
   9:              </StackPanel>
  10:          </DataTemplate>
  11:      </ListBox.ItemTemplate>
  12:  </ListBox>

Embedding Visio in a Web Application

Yes, it is also possible to embed Visio in a web application, or more precisely in a browser application. I believe those of you are pretty much familiar with WPF can guess that it is done with WPF Browser Applications (XBAP). That’s right.

I need to give a quick remark that there are some other ways of using Visio on the web. Of course, you can use a free Visio Web Viewer control that, however, has a somewhat limited API. You can even embed a fully-fledged Visio control in an HTML page and try to interact with it via JavaScript, however your UI capabilities will be limited.

So, the best way to go is to create a WPF Browser Application (XBAP). There is one important consideration though. Since, embedded Visio is an ActiveX control, an XBAP application containing it will require running in the full trust mode that grants access to your machine to a browser application. This mode is enabled by default in Internet Explorer for intranet websites, which are a common location for such applications. In order to use it on the Web you can either alter your IE security settings, so that it allows running XBAP application in full trust for every website, which is obviously not secure, or just to add your website to the trusted zone.

Marking a WPF Browser application as a full trust one is the first thing you should do after creating a project. Right-click on your project in the Solution Explorer, press ‘Properties’ and go to ‘Security’ and set ‘This is a full trust application’.

image

 

I won’t show you the source code here, because it is exactly the same as for a regular WPF application, except for some points where instead of Window you are using Page. You can still find the source code in the ZIP file I provide below.

Anyway, you should see something like that.

image

Conclusion

There are multiple reasons for extending Visio functionality. Also there are many ways of doing that. Although writing a Visio add-in often seems to be a reasonable idea, it is not always the case because of its limited UI capabilities. At the same time, it can be easily sorted out by writing a standalone desktop application that can be created with both Windows Forms and with powerful Windows Presentation Foundation.

Furthermore, if you want to ease deployment of your application and making it available to users immediately, you should consider an option of creating it as a browser application with XBAP.

Next Chapters

Analysing Parent-Child Relations in Visio

Understanding Visio Event Model

This is only the first article of the series. Next articles will focus more on the Visio object model that allows analysing diagrams and creating new ones programmatically. The Visio API is the same, no matter which you decide to create your application with, so those chapters will be useful for any case.

Stay tuned!

Download Source Code

Visio.zip (496.48 kb)

Kick it! Shout it

Tags: ,
Posted on Monday, September 05, 2011
Comments (0)
blog comments powered by Disqus