Getting started with WPF for AutoCAD API

Getting started with WPF for AutoCAD API

Basic Command

I've recently worked on a project where I had to create a WPF plugin for AutoCAD. And surprisingly, I was not able to find a single resource which talks about all the fundamentals of a WPF plugin and adding a Ribbon tab. So here is what I was able to figure out from multiple resources.

Before getting into creating a WPF plugin, you need to be aware of creating a basic AutoCAD plugin

Getting started with AutoCAD API Below links are a good place to start:
1. My First AutoCAD Plug-in Overview
2. Exercises: Create Your First Project
3. User interfaces with AutoCAD .NET
4. AutoCAD Training Material

Now that you know how to create a basic AutoCAD Plugin, lets start creating a WPF Plugin.

Setting up a new Visual Studio Project

Open a new instance of Visual Studio and create a "New Project". In the options to choose a "project template", choose "Class Library (.NET Framework)". (Tip: search for "dll" to shorten the list of templates). Then choose a desired name (eg: ProjectName) & folder for the project and click create. A new instance of a project with a blank "Class1.cs" will be created.

Adding AutoCAD .dll references

Now you need to add AutoCAD's dll references into you Visual Studio project so that you can make use of the AutoCAD API. To do this, right click on "references" in your Solution Explrore and choose add references. Then, choose "browse" at the bottom to browser for the below dll files based on you AutoCAD version

  1. AcMdg: C:\Program Files\Autodesk\AutoCAD 20xx\acmgd.dll
  2. AcDbMgd: C:\Program Files\Autodesk\AutoCAD 20xx\acdbmgd.dll
  3. AcCoreMgd: C:\Program Files\Autodesk\AutoCAD 20xx\accoremgd.dll

After adding these references, ctrl-click over each of the selected references, then right-click and choose Properties. In the Properties window, click the Copy Local field and then select False from the drop-down list.

Creating a new custom command

Check out the following links to know how AutoCAD looks for a custom API command (CommandClass & ExtensionApplication):

  1. Application Initialization and Load-Time Optimization (.NET)
  2. Optimizing the loading of AutoCAD .NET applications

Before adding a WPF window, lets create a new custom command which will later be used to call the WPF window. Below code is a referenced from the following Autodesk article to create a basic command using AutoCAD API which will create a new multiline text (MText) object in Model space.

Replace all the contents from your Class1.cs file with below code.

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
[assembly: CommandClass(typeof(AutoCAD_WPF_101.Class1))]
namespace AutoCAD_WPF_101
{
    public class Class1
    {
        [CommandMethod("AdskGreeting")]
        public static void AdskGreeting()
        {
            // Get the current document and database, and start a transaction
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;
            // Starts a new transaction with the Transaction Manager
            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                // Open the Block table record for read
                BlockTable acBlkTbl;
                acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId,
                                             OpenMode.ForRead) as BlockTable;
                // Open the Block table record Model space for write
                BlockTableRecord acBlkTblRec;
                acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace],
                                                OpenMode.ForWrite) as BlockTableRecord;
                /* Creates a new MText object and assigns it a location,
                text value and text style */
                MText objText = new MText();
                // Set the default properties for the MText object
                objText.SetDatabaseDefaults();
                // Specify the insertion point of the MText object
                objText.Location = new Autodesk.AutoCAD.Geometry.Point3d(2, 2, 0);
                // Set the text string for the MText object
                objText.Contents = "Greetings, Welcome to the AutoCAD .NET Developer's Guide";
                // Set the text style for the MText object
                objText.TextStyleId = acCurDb.Textstyle;
                // Appends the new MText object to model space
                acBlkTblRec.AppendEntity(objText);
                // Appends to new MText object to the active transaction
                acTrans.AddNewlyCreatedDBObject(objText, true);
                // Saves the changes to the database and closes the transaction
                acTrans.Commit();
            }
        }
    }
}

Build & Test the application

At this point, lets build the plugin and test it if the above command is working as expected. To do this, click on "Build solution" from the "Build" menu in the ribbon. Confirm that the build is succeeded from the output window - below is what you should see:

========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

This will create a new file called ProjectName.dll in ProjectFolder\bin\Debug\ folder of your project. Now open a blank drawing in AutoCAD and use the NETLOAD. Then browse to the ProjectFolder\bin\Debug\ folder and choose ProjectName.dll to load the plugin. Choose "load once" if you're prompted.

This will load the plugin and now you should be able to use the command AdskGreeting that we defined in the above Class1.cs. Using the AdskGreeting command will add a text in your Model space close to the origin.

Note: It's a good practice to keep testing your plugin as you continue to work on it.

WPF

Now that we have a working command, lets add a WPF window which we can use to run this command on a button click.

Creating a WPF Window

Right click on your project in Solution Explore and click "Add > New Item" and choose UserControl (WPF) from the window. Then rename the UserControl.xaml file to MainWindow.xaml and then replace <UserControl with <Window in the 1st line of XAML & MainWindow : UserControl with MainWindow : Window in your MainWindow.xaml.cs file. Now we have a blank WPF window ready.

Lets add a button into the window which we'll use later to trigger the AdskGreeting command.

<Button x:Name="button" Content="Button" HorizontalAlignment="Center" VerticalAlignment="Center"/>

Initiating the WPF window from the custom command

Now lets create a command which will open our WPF Window. We can add this command below the existing AdskGreeting command;

[CommandMethod("OpenWPFWindow")]
public void CmdOpenWPFWindow()
{
    var wpfWindow = new MainWindow();
    var wpfResult = AcAp.ShowModalWindow(expWindow);
}

Now lets call the AdskGreeting command when the button I clicked. Below is the final code

<Window x:Class="AutoCAD_WPF_101.MainWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:AutoCAD_WPF_101"
             mc:Ignorable="d"
             d:DesignHeight="150" d:DesignWidth="300">
    <Grid>
        <Button x:Name="button" Content="Button" HorizontalAlignment="Center" VerticalAlignment="Center" Click="button_Click"/>
    </Grid>
</Window>

using System.Windows;

namespace AutoCAD_WPF_101
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            Class1.AdskGreeting();
            this.Close(); // close the window to display the text added by the plugin in Model space
        }
    }
}

We now have a working code. Load the .dll using NETLOAD and use the command OpenWPFWindow which will open a WPF window in AutoCAD.

In the next article, we will talk about how to add a Ribbon in AutoCAD UI and how to distribute the plugin to other people.

Sample Code:

I've published an example repository on GitHub which you can clone and test this functionality