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.

Subscribe via RSS
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.
Posted by: Luis | July 02, 2007 at 04:31 PM
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?
Posted by: Tom | July 06, 2007 at 05:37 AM
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
Posted by: Kean | July 06, 2007 at 11:39 AM
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!
Posted by: Luis | July 07, 2007 at 04:38 AM
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
Posted by: Kean | July 09, 2007 at 03:21 PM
Hi Kean,
is it possible to have some examples of dockable modelss dialogs using .Net? (no palettes)
thanks a lot in advance
David
Posted by: David | July 20, 2007 at 04:11 PM
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
Posted by: Kean | July 20, 2007 at 06:49 PM
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
Posted by: David | August 08, 2007 at 02:18 PM
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
Posted by: Kean | August 08, 2007 at 06:51 PM
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.
Posted by: Nabil Sleiman | August 22, 2008 at 01:51 AM
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
Posted by: Kean | August 22, 2008 at 08:11 AM