access entity event after transaction

access entity event after transaction

Anonymous
Not applicable
3,368 Views
15 Replies
Message 1 of 16

access entity event after transaction

Anonymous
Not applicable

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.

0 Likes
3,369 Views
15 Replies
Replies (15)
Message 2 of 16

_gile
Consultant
Consultant

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}");
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 16

Anonymous
Not applicable

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?

0 Likes
Message 4 of 16

_gile
Consultant
Consultant

You have to set some 'marker' to the watched polylines (xdata or extension dictionary xrecord) or store the polyline handles in a drawing dictionary so that you're able to retrieve these polylines to reset their event handlers.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 16

Anonymous
Not applicable

Do you have a little example how this should look like?

I can't imagine right now how to handle the attached xdata.

0 Likes
Message 6 of 16

_gile
Consultant
Consultant

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();
            }
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 7 of 16

Anonymous
Not applicable

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?

0 Likes
Message 8 of 16

_gile
Consultant
Consultant

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);
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 9 of 16

Anonymous
Not applicable

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...

0 Likes
Message 10 of 16

Anonymous
Not applicable

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...

0 Likes
Message 11 of 16

_gile
Consultant
Consultant

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.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 12 of 16

Anonymous
Not applicable

Yes, when I put a breakpoint to this point it runs like in your description.

0 Likes
Message 13 of 16

_gile
Consultant
Consultant

And if you run a 'step by step' after the break point does it reach:

pline.Modified += Pline_Modified;

?

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 14 of 16

Anonymous
Not applicable

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.

0 Likes
Message 15 of 16

_gile
Consultant
Consultant

I'm afraid I cannot help you further.

The code I purposed works as expected with AutoCAD.

May be an issue with BricsCAD...



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 16 of 16

Anonymous
Not applicable

Too bad.

But thanks a lot for your efforts!

0 Likes