November 2014

Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            










« Importing Photosynth point clouds into AutoCAD 2011 - Part 2 | Main | April's plugin of the Month: XrefStates for AutoCAD »

April 13, 2010

Adding to AutoCAD’s Application Menu and Quick Access Toolbar using .NET

I received this question from Vikas Hajela a few days ago:

I am developing a plugin in C#, which will add a link in Quick Access Toolbar in AutoCAD. […] My problem is that I don’t know how to add a link into existing Quick Access Toolbar and Menu Bar in AutoCAD using ObjectARX SDK and C#. Also I want that on click of that link it should open a new window.

We’re going to look at some code that – on initialization of the application – adds an item to AutoCAD’s “Big A” Application Menu and to the Quick Access Toolbar (the “quick launch” toolbar towards the left of the main application window’s title bar). To solve this I borrowed some code and techniques from a couple of DevNotes on the ADN site: Use the .NET API to add a menu Item to Application Menu (big A) and The arrow of the Dialog Launcher button on my Ribbon panel does not show. It should be noted that this code will need at least AutoCAD 2010 to execute.

Here’s the C# code. To make it work you will need to place a couple of .ico files in your DLL’s folder (these could very easily be stored as resources in your application’s project, which is left as an exercise for the reader).

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.Windows;

using System.Windows.Media.Imaging;

using System.Reflection;

using System.IO;

using System.Collections.Generic;

using System;

 

namespace AppMenus

{

  public class ExtApp : IExtensionApplication

  {

    // String constants

 

    const string appText = "Browse Photosynth";

    const string appDesc =

      "Browse the Photosynth site and import point " +

      "clouds into AutoCAD.";

    const string smallFile = "Browser-16x16.ico";

    const string largeFile = "Browser-32x32.ico";

    const string bpCmd = "_.BP";

 

    public void Initialize()

    {

      // We defer the creation of our Application Menu to when

      // the menu is next accessed

 

      ComponentManager.ApplicationMenu.Opening +=

        new EventHandler<EventArgs>(ApplicationMenu_Opening);

 

      // We defer the creation of our Quick Access Toolbar item

      // to when the application is next idle

 

      Application.Idle += new EventHandler(Application_OnIdle);

    }

 

    public void Terminate()

    {

      // Assuming these events have fired, they have already

      // been removed

 

      ComponentManager.ApplicationMenu.Opening -=

        new EventHandler<EventArgs>(ApplicationMenu_Opening);

 

      Application.Idle -= new EventHandler(Application_OnIdle);

    }

 

    void Application_OnIdle(object sender, EventArgs e)

    {

      // Remove the event when it is fired

 

      Application.Idle -= new EventHandler(Application_OnIdle);

 

      // Add our Quick Access Toolbar item

 

      AddQuickAccessToolbarItem();

    }

 

    void ApplicationMenu_Opening(object sender, EventArgs e)

    {

      // Remove the event when it is fired

 

      ComponentManager.ApplicationMenu.Opening -=

        new EventHandler<EventArgs>(ApplicationMenu_Opening);

 

      // Add our Application Menu

 

      AddApplicationMenu();

    }

 

    private void AddApplicationMenu()

    {

      ApplicationMenu menu = ComponentManager.ApplicationMenu;

      if (menu != null && menu.MenuContent != null)

      {

        // Create our Application Menu Item

 

        ApplicationMenuItem mi = new ApplicationMenuItem();

        mi.Text = appText;

        mi.Description = appDesc;

        mi.LargeImage = GetIcon(largeFile);

 

        // Attach the handler to fire out command

 

        mi.CommandHandler = new AutoCADCommandHandler(bpCmd);

 

        // Add it to the menu content

 

        menu.MenuContent.Items.Add(mi);

      }

    }

 

    private void AddQuickAccessToolbarItem()

    {

      Autodesk.Windows.ToolBars.QuickAccessToolBarSource qat =

        ComponentManager.QuickAccessToolBar;

      if (qat != null)

      {

        // Create our Ribbon Button

 

        RibbonButton rb = new RibbonButton();

        rb.Text = appText;

        rb.Description = appDesc;

        rb.Image = GetIcon(smallFile);

 

        // Attach the handler to fire out command

 

        rb.CommandHandler = new AutoCADCommandHandler(bpCmd);

 

        // Add it to the Quick Access Toolbar

 

        qat.AddStandardItem(rb);

      }

    }

 

    private System.Windows.Media.ImageSource GetIcon(string ico)

    {

      // We'll look for our icons in the folder of the assembly

      // (we could also use a resources, of course)

 

      string path =

        Path.GetDirectoryName(

          Assembly.GetExecutingAssembly().Location

        );

 

      // Check our .ico file exists

 

      string fileName = path + "\\" + ico;

      if (File.Exists(fileName))

      {

        // Get access to it via a stream

 

        Stream fs =

          new FileStream(

            fileName,

            FileMode.Open,

            FileAccess.Read,

            FileShare.Read

          );

        using (fs)

        {

          // Decode the contents and return them

 

          IconBitmapDecoder dec =

            new IconBitmapDecoder(

              fs,

              BitmapCreateOptions.PreservePixelFormat,

              BitmapCacheOption.Default

            );

          return dec.Frames[0];

        }

      }

      return null;

    }

  }

 

  // A class to fire commands to AutoCAD

 

  public class AutoCADCommandHandler

    : System.Windows.Input.ICommand

  {

    private string _command = "";

 

    public AutoCADCommandHandler(string cmd)

    {

      _command = cmd;

    }

 

#pragma warning disable 67

    public event EventHandler CanExecuteChanged;

#pragma warning restore 67

 

    public bool CanExecute(object parameter)

    {

      return true;

    }

 

    public void Execute(object parameter)

    {

      if (!String.IsNullOrEmpty(_command))

      {

        Document doc =

          Application.DocumentManager.MdiActiveDocument;

        doc.SendStringToExecute(

          _command + " ", false, false, false

        );

      }

    }

  }

}

A few comments on the code:

  • We delay the creation of both the Application Menu and Quick Access Toolbar items, but for different reasons:
    • The Application Menu only gets created when it’s first accessed, so we need to wait for that to happen before adding our item
    • The Quick Access Toolbar item cannot be created on Initialize(), as our module may have been loaded on AutoCAD startup and the QAT may not yet be ready
  • We have temporarily disabled a warning (CS0067) which tells us that an event handler – which we need to implement to complete the ICommand interface – is not used in our code

Now let’s see it in action. As you can probably tell from the code, it’s basically adding a “launch” UI to the application I showed in the last post.

When we NETLOAD the application (or auto-load it on AutoCAD start-up), we see our Quick Access Toolbar icon gets added:

Quick Access Toolbar icon added

We get more information when we hover over it:

Hovering over our new QAT icon

We also have our new Application Menu item:

And our new Application Menu item When we select either item, our BP command – as implemented previously – gets launched. Vikas had requested a dialog be shown, but I strongly recommend that this is implemented via a command rather than being displayed directly in the code. This just helps AutoCAD synchronise its user interface appropriately and will avoid lots of subtle issues you might otherwise hit.

blog comments powered by Disqus

Feed/Share

10 Random Posts