Hi all,
I want to programm a command with events. It should run like this:
First I make a prompt to pick a polyline. Then I put a event on this polyline, for example modified.
And when I modify the polyline the area of the polyline should be shown in a message box.
How can this event get triggered after the transaction has been ended?
Thank you.
Hi,
using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Runtime; using System; using AcCoreAp = Autodesk.AutoCAD.ApplicationServices.Core.Application; namespace ObjectModifiedEventSample { public class Commands { [CommandMethod("TEST")] public static void Test() { var doc = AcCoreAp.DocumentManager.MdiActiveDocument; var db = doc.Database; var ed = doc.Editor; var options = new PromptEntityOptions("\nSelect Polyline: "); options.SetRejectMessage("\nSelected object is not a Polyline."); options.AddAllowedClass(typeof(Polyline), true); var result = ed.GetEntity(options); if (result.Status != PromptStatus.OK) return; using (var tr = db.TransactionManager.StartTransaction()) { var pline = (Polyline)tr.GetObject(result.ObjectId, OpenMode.ForRead); pline.Modified += Pline_Modified; tr.Commit(); } } private static void Pline_Modified(object sender, EventArgs e) { var pline = (Polyline)sender; AcCoreAp.ShowAlertDialog($"Area = {pline.Area}"); } } }
Thank you @_gile for the example, that's it.
When I save and close the document with the polyline and open it afterwards the event does not exist anymore. So I have to call the command again with every session.
Is it possible to programm it that the event is saved and i do not have to call the command everytime again?
Do you have a little example how this should look like?
I can't imagine right now how to handle the attached xdata.
Here's an example using a named dictionary to store the 'watched polylines' identifiers.
The WatchedPolyline class
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using System;
using System.Linq;
using AcCoreAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
namespace ObjectModifiedEventSample
{
class WatchedPolyline
{
static string dictName = "GILE_MODIFIED_EVENT";
static string xrecName => "WatchedPlines";
public static void Pline_Modified(object sender, EventArgs e)
{
var pline = (Polyline)sender;
AcCoreAp.ShowAlertDialog($"Area = {pline.Area}");
}
public static void AddPolyline(Transaction tr, Polyline pline)
{
var db = pline.Database;
var NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
DBDictionary dict;
if (NOD.Contains(dictName))
{
dict = (DBDictionary)tr.GetObject(NOD.GetAt(dictName), OpenMode.ForRead);
}
else
{
tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForWrite);
dict = new DBDictionary();
NOD.SetAt(dictName, dict);
tr.AddNewlyCreatedDBObject(dict, true);
}
Xrecord xrec;
ResultBuffer data;
if (dict.Contains(xrecName))
{
xrec = (Xrecord)tr.GetObject(dict.GetAt(xrecName), OpenMode.ForWrite);
data = xrec.Data;
if (!data.Cast<TypedValue>().Any(tv => tv.Value.Equals(pline.ObjectId)))
{
data.Add(new TypedValue(330, pline.ObjectId));
pline.Modified += Pline_Modified;
}
}
else
{
xrec = new Xrecord();
dict.SetAt(xrecName, xrec);
tr.AddNewlyCreatedDBObject(xrec, true);
data = new ResultBuffer(new TypedValue(330, pline.ObjectId));
pline.Modified += Pline_Modified;
}
xrec.Data = data;
}
public static void UpdatePolylines(Document doc)
{
var db = doc.Database;
using (doc.LockDocument())
using (var tr = db.TransactionManager.StartOpenCloseTransaction())
{
var NOD = (DBDictionary)tr.GetObject(db.NamedObjectsDictionaryId, OpenMode.ForRead);
if (NOD.Contains(dictName))
{
var dict = (DBDictionary)tr.GetObject(NOD.GetAt(dictName), OpenMode.ForRead);
if (dict.Contains(xrecName))
{
var xrec = (Xrecord)tr.GetObject(dict.GetAt(xrecName), OpenMode.ForWrite);
var data = new ResultBuffer();
foreach (TypedValue typedValue in xrec.Data)
{
var id = (ObjectId)typedValue.Value;
if (id.IsErased)
continue;
var pline = (Polyline)tr.GetObject(id, OpenMode.ForRead);
pline.Modified += Pline_Modified;
data.Add(typedValue);
}
xrec.Data = data;
}
}
tr.Commit();
}
}
}
}
The Initialization class
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using System;
using AcCoreAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
namespace ObjectModifiedEventSample
{
public class Initialization : IExtensionApplication
{
public void Initialize()
{
AcCoreAp.Idle += OnIdle;
}
private void OnIdle(object sender, EventArgs e)
{
var docs = AcCoreAp.DocumentManager;
var acDoc = docs.MdiActiveDocument;
if (acDoc != null)
{
AcCoreAp.Idle -= OnIdle;
foreach (Document doc in docs)
{
WatchedPolyline.UpdatePolylines(doc);
}
docs.DocumentCreated += Docs_DocumentCreated;
}
}
public void Terminate()
{ }
private void Docs_DocumentCreated(object sender, DocumentCollectionEventArgs e) =>
WatchedPolyline.UpdatePolylines(e.Document);
}
}
The Commands class
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using AcCoreAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
namespace ObjectModifiedEventSample
{
public class Commands
{
[CommandMethod("TEST")]
public static void Test()
{
var doc = AcCoreAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var options = new PromptEntityOptions("\nSelect Polyline: ");
options.SetRejectMessage("\nSelected object is not a Polyline.");
options.AddAllowedClass(typeof(Polyline), true);
var result = ed.GetEntity(options);
if (result.Status != PromptStatus.OK)
return;
using (var tr = db.TransactionManager.StartTransaction())
{
var pline = (Polyline)tr.GetObject(result.ObjectId, OpenMode.ForRead);
WatchedPolyline.AddPolyline(tr, pline);
tr.Commit();
}
}
}
}
Thank you @_gile
Since I have this example in my .dll my BricsCAD does not really run when I load the .dll file. Then it is very slow that you can't work with it.
I think it is because of the initialization class. When I comment this out it runs normal.
Do you know how I can solve this?
This is probably dur to BricsCAD because I do not notice such problem with AutoCAD.
The initialization class is required to register the DocumentCreated and run UpdatePolylines on each already opened document when the application is loaded.
You can try to avoid the Idle event handling (not tested).
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using System;
using AcCoreAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
namespace ObjectModifiedEventSample
{
public class Initialization : IExtensionApplication
{
public void Initialize()
{
var docs = AcCoreAp.DocumentManager;
foreach (Document doc in docs)
{
WatchedPolyline.UpdatePolylines(doc);
}
docs.DocumentCreated += Docs_DocumentCreated;
}
public void Terminate()
{ }
private void Docs_DocumentCreated(object sender, DocumentCollectionEventArgs e) =>
WatchedPolyline.UpdatePolylines(e.Document);
}
}
Thank you. With this initialization part it runs well when I use the command.
But when I safe, close and reopen the document the event is not safed...
And I tried the original initialization class in c# now and this runs. (Because first I only tried in VB.NET)
But it is the same problem that the event is not safed...
When the application is loaded, the Initialize method is run and the event handlers should be add to the 'watched polylines' of every opened drawing, idem for each later created document because of the DocumentCreated handler.
Try putting a breakpoint at the beginning of the WatchedPolyline.UpdatePolylines() method, the execution should stop for each already opened document when the application is loaded and for each later created document.
Yes, when I put a breakpoint to this point it runs like in your description.
When I start debugging and open the application it skips that line because it does not get in this foreach loop.
When I draw a polyline and make the TEST command it reaches your line in the AddPolyline method.
When I save, close and reopen the drawing it reaches the line in UpdatePolylines method.
But when I step foreward and get back to the drawing the event does no more work.