Using a modeless .NET dialog to display AutoCAD object properties

In this previous post we looked at creating a simple modal dialog and using it to display object properties. This post looks at the structural changes you need to make to your application for the same dialog to be used modelessly. In a later post we'll look at the benefits you get from leveraging the Palette system for modeless interaction inside AutoCAD.

Firstly, let's think about the interaction paradigm needed by a modeless dialog. A few things come to mind:

  • There is no longer a need to hide and show the dialog around selection
  • Rather than asking the user to select an entity, it's neater to respond to standard selection events
  • We no longer need a "browse" button
  • We now need to be more careful about document access
    • Our command automatically locked the document (and had sole access) in the modal example
    • We should now lock it "manually" when we access it

So we can already simplify our dialog class - here's some modified C# code, with the browse button removed and document-locking in place:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace CustomDialogs

{

  public partial class TypeViewerForm : Form

  {

    public TypeViewerForm()

    {

      InitializeComponent();

    }

    public void SetObjectText(string text)

    {

      typeTextBox.Text = text;

    }

    public void SetObjectId(ObjectId id)

    {

      if (id == ObjectId.Null)

      {

        SetObjectText("");

      }

      else

      {

        Document doc =

          Autodesk.AutoCAD.ApplicationServices.

            Application.DocumentManager.MdiActiveDocument;

        DocumentLock loc =

          doc.LockDocument();

        using (loc)

        {

          Transaction tr =

            doc.TransactionManager.StartTransaction();

          using (tr)

          {

            DBObject obj = tr.GetObject(id, OpenMode.ForRead);

            SetObjectText(obj.GetType().ToString());

            tr.Commit();

          }

        }

      }

    }

    private void closeButton_Click(object sender, EventArgs e)

    {

      this.Close();

    }

  }

}

So which event should we respond to, to find out when objects are selected? In this case I chose a PointMonitor - this class tells you a lot of really useful information about the current selection process. It also has the advantage of picking up the act of hovering over objects - no need for selection to actually happen. One other fun option would have been to use a Database event (ObjectAppended) to display information about objects as they are added to the drawing.

A few other comments about the code:

  • Predictably enough we now use ShowModelessDialog rather than ShowModalDialog()
  • We have our form as a member variable of the class, as its lifespan goes beyond the command we use to show it
  • I've also removed the selection code; we're no longer asking for objects to be selected

Here's the updated command implementation:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System;

using CustomDialogs;

namespace CustomDialogs

{

  public class Commands

  {

    TypeViewerForm tvf;

    public Commands()

    {

      tvf = new TypeViewerForm();

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;

      ed.PointMonitor +=

        new PointMonitorEventHandler(OnMonitorPoint);

    }

    ~Commands()

    {

      try

      {

        tvf.Dispose();

        Document doc =

          Application.DocumentManager.MdiActiveDocument;

        Editor ed = doc.Editor;

        ed.PointMonitor -=

          new PointMonitorEventHandler(OnMonitorPoint);

      }

      catch(System.Exception)

      {

        // The editor may no longer

        // be available on unload

      }

    }

    private void OnMonitorPoint(

      object sender,

      PointMonitorEventArgs e

    )

    {

      FullSubentityPath[] paths =

        e.Context.GetPickedEntities();

      if (paths.Length <= 0)

      {

        tvf.SetObjectId(ObjectId.Null);

        return;

      };

      ObjectId[] objs = paths[0].GetObjectIds();

      if (objs.Length <= 0)

      {

        tvf.SetObjectId(ObjectId.Null);

        return;

      };

      // Set the "selected" object to be the last in the list

      tvf.SetObjectId(objs[objs.Length - 1]);

    }

    [CommandMethod("vt",CommandFlags.UsePickSet)]

    public void ViewType()

    {

      Application.ShowModelessDialog(null, tvf, false);

    }

  }

}

And here's the source project for this version of the application. When you run the application you may experience issues with the dialog getting/retaining focus - this is generally a problem with modeless dialogs that has been addressed automatically by the Palette class, something we'll take a look at in a future post.

16 responses to “Using a modeless .NET dialog to display AutoCAD object properties”

  1. Thank you for the code sample, and I have a question?

    If you have for example, a polyline in the for of a slot when two of the sides have an arc, and you have other polylines that meet those sides and all around that slot to leave it as an island.

    Pointmonitor do not work and I have seen other cases where fail to select.

    Is there something we can do?

    I have tried to use this class before in one of my commands to select closed areas but not always was giving me the right one.

    Then, I end up making a selection of the closed polylines on the screen and using a function to select the polyline by defining an internal point, instead.

    Thanks!
    Luis.

  2. I have been using PointMonitor to display information about the entity via AppendToolTipText. It works great except for one thing: My drawing is mostly solids and if I hover over a solid so that it is highlighted, it will actually display the information of the solid that is behind the object that I'm trying to get the information for.

    How can I assure that I get the information for the object that is being highlighted?

  3. Kean Walmsley Avatar

    Luis -

    I'm afraid your description of the geometry isn't clear to me. Are you trying to detect when the cursor is hovering within a particular object? Unfortunately "pick in space" is not enabled when hovering over objects - the PointMonitor doesn't pick them up. Unless I've misunderstood...

    Tom -

    I'm not sure why this is happening. One thought is to make sure you're not picking the wrong item from the list (assuming there are more than one entity returned by the PointMonitor). I tried to reproduce the problem in my own code, but it seemed to work OK - a lot may depend on which visual style you're working with, etc.

    Regards,

    Kean

  4. Kean;

    Excuse my bad explanation 🙁

    Let see if I can explain better this time, by providing a short sample that can give you an idea:

    Draw an ellipse (with pellipse=1), then draw a rectangle to enclosure that ellipse in the center.

    Then, draw a line that divides the rectangle, can be drawn vertical or horizontal. Then use the command bpoly and generate two new closed polylines in the areas between the rectangle and the ellipse on the center.

    Erase, the original rectangle, and the line, and now call or use the pointmonitor, it won't select the ellipse, I know it can be brought up with draworder and later use the pointmonitor.

    The sample I provided it is very simple, but in the case I was thinking of using it it gets more complex, and the idea is have an easy selection, that's why I end up using a point inside the areas.

    Hope, you are not sleep when reading this last line.

    Thanks!

  5. Kean Walmsley Avatar

    Luis,

    I think the PointMonitor is working OK... check out the latest post in this series to see if the code in there helps.

    Regards,

    Kean

  6. Hi Kean,
    is it possible to have some examples of dockable modelss dialogs using .Net? (no palettes)
    thanks a lot in advance
    David

  7. Kean Walmsley Avatar

    Hi David,

    The parent of CAdUiPaletteSet (the internal MFC/ObjectARX class the PaletteSet wraps) is CAdUiDockControlBar, which is not exposed through the .NET API.

    So PaletteSet is currently the way to go for implementing a dockable modeless UI inside AutoCAD using .NET.

    Is there a particular reason you'd prefer not to use it?

    Regards,

    Kean

  8. Hi,
    1)loading
    2)calling "VT"
    3)terminating the dialogbox
    4)recalling "VT" --> Throws an Exception! (Can't access the object, Objectname: TypeViewerForm)
    Regards,
    David

  9. Hi David,

    It seems the form is betting disposed, and we then want to bring it up again. One option is to call this.Hide() in the closebutton handler, but we'd then have to set the dialog not to show the "X" button.

    The better option is probably to check for the availability of the form inside the VT command implementation, creating it again, as necessary:

    [CommandMethod("vt",CommandFlags.UsePickSet)]
    public void ViewType()
    {
    if (tvf == null || tvf.IsDisposed)
    tvf = new TypeViewerForm();
    Application.ShowModelessDialog(null, tvf, false);
    }

    Cheers,

    Kean

  10. Hi Kean, sorry if this is not relevant, but I would like to draw the AutoCAD objects like lines and circles on the dialog itself (or part of the dialog, a dialog item). Is this possible?
    Your help is greatly appreciated.
    Cheers, Nabil.

  11. Hi Nabil,

    If you need to display entities from a drawing or even temporary entities you add on the fly, you should look at the BlockView sample.

    Regards,

    Kean

  12. ".. you may experience issues with the dialog getting/retaining focus - this is generally a problem with modeless dialogs.."

    Hi Kean,

    Would you please help me in finding a way to get/retain focus in a modeless form?

    Many Thanks,

  13. Kean Walmsley Avatar

    Hi ali,

    I can't, right now. You might try posting to the AutoCAD .NET discussion group, to see if someone there can help.

    Regards,

    Kean

  14. Friend would like to know, if you have lessons made by Autodesk regarding developing AUTOCAD + WINDOWS FORM C # plugins
    Thank you
    I'm waiting

    1. Kean Walmsley Avatar

      All resources Autodesk provides in this regard will be available at the AutoCAD Developer Center:

      autodesk.com/develop...

      Kean

  15. Francisco Andres Pinzon Santoy Avatar
    Francisco Andres Pinzon Santoy

    Autocad.NEt Version 23 for Autocad 2020

Leave a Reply to Francisco Andres Pinzon Santoy Cancel reply

Your email address will not be published. Required fields are marked *