April 13, 2010

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.

Here’s the C# code. To make it work you will need to place a coupleof .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

{

publicclassExtApp : IExtensionApplication

{

// String constants

conststring appText = "Browse Photosynth";

conststring appDesc =

"Browse the Photosynth site and import point " +

"clouds into AutoCAD.";

conststring smallFile = "Browser-16x16.ico";

conststring largeFile = "Browser-32x32.ico";

conststring bpCmd = "_.BP";

publicvoid Initialize()

{

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

// the menu is next accessed

ComponentManager.ApplicationMenu.Opening +=

newEventHandler<EventArgs>(ApplicationMenu_Opening);

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

// to when the application is next idle

Application.Idle += newEventHandler(Application_OnIdle);

}

publicvoid Terminate()

{

// Assuming these events have fired, they have already

// been removed

ComponentManager.ApplicationMenu.Opening -=

newEventHandler<EventArgs>(ApplicationMenu_Opening);

Application.Idle -= newEventHandler(Application_OnIdle);

}

void Application_OnIdle(object sender, EventArgs e)

{

// Remove the event when it is fired

Application.Idle -= newEventHandler(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 -=

newEventHandler<EventArgs>(ApplicationMenu_Opening);

// Add our Application Menu

AddApplicationMenu();

}

privatevoid AddApplicationMenu()

{

ApplicationMenu menu = ComponentManager.ApplicationMenu;

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

{

// Create our Application Menu Item

ApplicationMenuItem mi = newApplicationMenuItem();

mi.Text = appText;

mi.Description = appDesc;

mi.LargeImage = GetIcon(largeFile);

// Attach the handler to fire out command

mi.CommandHandler = newAutoCADCommandHandler(bpCmd);

// Add it to the menu content

menu.MenuContent.Items.Add(mi);

}

}

privatevoid AddQuickAccessToolbarItem()

{

Autodesk.Windows.ToolBars.QuickAccessToolBarSource qat =

ComponentManager.QuickAccessToolBar;

if (qat != null)

{

// Create our Ribbon Button

RibbonButton rb = newRibbonButton();

rb.Text = appText;

rb.Description = appDesc;

rb.Image = GetIcon(smallFile);

// Attach the handler to fire out command

rb.CommandHandler = newAutoCADCommandHandler(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 =

newFileStream(

fileName,

FileMode.Open,

FileAccess.Read,

FileShare.Read

);

using (fs)

{

// Decode the contents and return them

IconBitmapDecoder dec =

newIconBitmapDecoder(

fs,

BitmapCreateOptions.PreservePixelFormat,

BitmapCacheOption.Default

);

return dec.Frames[0];

}

}

returnnull;

}

}

// A class to fire commands to AutoCAD

publicclassAutoCADCommandHandler

: System.Windows.Input.ICommand

{

privatestring _command = "";

public AutoCADCommandHandler(string cmd)

{

_command = cmd;

}

#pragma warning disable 67

publiceventEventHandler CanExecuteChanged;

#pragma warning restore 67

publicbool CanExecute(object parameter)

{

returntrue;

}

publicvoid 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 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.