[AI Readability Summary] EntityJig is the core base class for interactive single-entity dragging in AutoCAD .NET. It solves unstable previews, blurred responsibilities, and entity lifecycle issues during interactive drawing. Key concepts: automatic redraw, the Sampler/Update loop, and Entity lifecycle management. Keywords: EntityJig, DrawJig, AutoCAD .NET.
The technical specification snapshot makes the context clear
| Parameter | Description |
|---|---|
| Language | C# / .NET |
| Platform | AutoCAD .NET API |
| Underlying protocol/framework | Managed wrapper over ObjectARX |
| Core classes | Jig, EntityJig, DrawJig |
| Interaction entry point | Editor.Drag() |
| Core dependencies | Autodesk.AutoCAD.EditorInput, DatabaseServices, Geometry |
| Typical entities | Line, Circle, BlockReference |
| Common pain points | eKeyNotFound, incorrect WorldDraw overrides, entities not released after cancel |
The responsibilities of EntityJig must stay strictly limited
EntityJig is not a generic dynamic drawing framework. It is only responsible for the interactive update and preview of a single Entity. After the developer hands a temporary entity to the base class, the framework automatically handles redraw during dragging.
Many failed implementations are not caused by API complexity, but by reversed responsibilities: EntityJig manages entities, while DrawJig manages custom geometry rendering. If you need to manually implement WorldDraw(), you usually should not keep using EntityJig.
The class hierarchy from ObjectARX to .NET defines the usage boundary
// Responsibility layers in the Jig abstraction system
Jig
├── EntityJig // Single-entity preview, automatically calls Entity.WorldDraw()
└── DrawJig // Multi-primitive/custom geometry, requires a manual WorldDraw()
This hierarchy shows a simple truth: if you choose the wrong base class, every implementation detail that follows will drift away from the correct model.
The core mechanism of EntityJig is a two-phase Sampler and Update loop
A complete drag operation is essentially a loop driven by Editor.Drag(jig). When the user moves the mouse, the framework samples input first, then decides whether to update the entity, and finally redraws automatically.
If Sampler() returns NoChange, Update() does not run. This is the key mechanism for reducing flicker and avoiding unnecessary refreshes. High-quality implementations usually enforce performance control at the sampling stage.
The standard execution order can be summarized in three steps
// Pseudocode: typical EntityJig execution flow
while (dragging)
{
var sample = Sampler(prompts); // Sample user input
if (sample == SamplerStatus.Cancel) // User canceled
break;
if (sample == SamplerStatus.OK)
{
Update(); // Write the new value back to the entity
// The framework automatically calls Entity.WorldDraw() for preview
}
}
This pseudocode makes the design explicit: Update() only changes data. Your business logic does not draw directly.
Entity lifecycle management determines whether the code remains stable
The Entity passed into an EntityJig constructor is often still a temporary object and has not yet been added to the database. Only after a successful drag should you append it to model space. If the drag is canceled, you must explicitly release it.
This is the root cause of many exceptions: the entity exists during the jig, but it does not automatically belong to the database. If you forget to call Dispose() on cancel, long-running plugins can easily accumulate resource leaks and state pollution.
A minimal LineJig implementation is enough to demonstrate the pattern
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
public class LineJig : EntityJig
{
private readonly Point3d _startPoint;
private Point3d _endPoint;
public LineJig(Point3d startPoint) : base(new Line(startPoint, startPoint))
{
_startPoint = startPoint;
_endPoint = startPoint;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var options = new JigPromptPointOptions("\nSpecify line endpoint:")
{
UseBasePoint = true,
BasePoint = _startPoint // Generate a rubber-band preview from the start point
};
var result = prompts.AcquirePoint(options);
if (result.Status == PromptStatus.Cancel)
return SamplerStatus.Cancel;
if (_endPoint.DistanceTo(result.Value) < Tolerance.Global.EqualPoint)
return SamplerStatus.NoChange; // Skip refresh when the coordinate is effectively unchanged
_endPoint = result.Value;
return SamplerStatus.OK;
}
protected override bool Update()
{
var line = (Line)Entity;
line.StartPoint = _startPoint;
line.EndPoint = _endPoint; // Only update the entity's geometric properties
return true;
}
}
This code shows the standard EntityJig pattern: Sampler() reads values, Update() writes values, and the framework handles redraw.
CircleJig shows that the sample type can change while the pattern stays the same
A line usually samples a point, while a circle usually samples a distance. Even though the input type changes, the programming model of EntityJig does not: collect input first, then write it back to entity properties.
This consistency matters. It means you can extend the same interaction model to circles, arcs, block references, and even custom entities without redesigning the preview mechanism from scratch.
Updating the radius through AcquireDistance matches circle semantics better
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var options = new JigPromptDistanceOptions("\nSpecify circle radius:")
{
UseBasePoint = true,
BasePoint = _center,
Cursor = CursorType.RubberBand
};
var result = prompts.AcquireDistance(options);
if (result.Status == PromptStatus.Cancel)
return SamplerStatus.Cancel;
if (Math.Abs(result.Value - _radius) < Tolerance.Global.EqualPoint)
return SamplerStatus.NoChange; // Avoid flicker caused by redundant updates
_radius = result.Value;
return SamplerStatus.OK;
}
The main value of this code is semantic clarity: using distance to represent radius creates a more direct interaction model and feels closer to native AutoCAD commands.
DrawJig fits multi-primitive or pure geometry preview scenarios
Scenarios such as rectangles, double-line walls, or auxiliary markers often need to display multiple edges or composite graphics at the same time. In these cases, EntityJig is no longer a good fit because it binds to only one entity.
If the preview itself is not a single entity but a temporary collection of geometry, you should switch to DrawJig and implement WorldDraw() manually.
Rectangle preview requires manual geometry drawing
protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
{
var p1 = _basePoint;
var p2 = new Point3d(_currentPoint.X, _basePoint.Y, 0);
var p3 = _currentPoint;
var p4 = new Point3d(_basePoint.X, _currentPoint.Y, 0);
draw.Geometry.Polygon(new[] { p1, p2, p3, p4 }); // Draw the rectangle boundary in a single pass
return true;
}
This code makes the boundary explicit: WorldDraw() belongs to DrawJig, not to an EntityJig subclass.
The most common mistakes come from three misconceptions
First, developers do not release temporary entities after a canceled drag. Second, Sampler() returns OK even when nothing changed, which causes excessive refreshes. Third, they try to override WorldDraw() inside an EntityJig subclass.
These issues may look minor, but they directly affect stability, performance, and maintainability. The second problem in particular is often misdiagnosed as an AutoCAD rendering issue, when the real cause is poor sampling logic.
The cancel path must clean up resources explicitly
if (dragRes.Status == PromptStatus.OK)
{
// Append to the database only after confirmation
btr.AppendEntity(jig.Entity);
tr.AddNewlyCreatedDBObject(jig.Entity, true);
}
else
{
jig.Entity.Dispose(); // Release the temporary entity when canceled
}
This code emphasizes a critical rule: database persistence and temporary resource cleanup must be handled through separate exit paths in your command logic.
The choice between EntityJig and DrawJig should depend on the preview object
If you are dragging only a line, a circle, or a block reference, use EntityJig. If you need to preview multiple segments, construction guides, dimension markers, or algorithmically generated temporary graphics, use DrawJig.
The real decision criterion is not which API is more powerful. It is whether the preview object naturally maps to a single Entity. This rule is more reliable than memorizing API names.
FAQ answers the most common implementation questions
Q1: Why does overriding WorldDraw in my EntityJig subclass cause errors or abnormal behavior?
Because EntityJig is designed to manage a single entity and let the framework automatically call that entity’s WorldDraw(). If you need manual drawing, use DrawJig instead.
Q2: Why is SamplerStatus.NoChange important?
It prevents meaningless Update() calls and redraws, significantly reduces flicker, improves drag smoothness, and provides one of the most direct performance optimizations for high-frequency interactive workflows.
Q3: Does the Entity already belong to the database during the jig?
Usually not. It is only a temporary entity. You should append it to model space through a transaction only after the user confirms the operation. If the user cancels, you must call Dispose() manually.
The core takeaways define the correct implementation model
This article systematically breaks down the responsibility boundary, execution loop, and lifecycle management of EntityJig in AutoCAD .NET development. It also highlights the fundamental difference between EntityJig and DrawJig, then uses LineJig, CircleJig, and rectangle preview examples to summarize the correct implementation pattern and the most common pitfalls.