Copying entities with xdata between drawings

Copying entities with xdata between drawings

SRSDS
Advisor Advisor
1,150 Views
5 Replies
Message 1 of 6

Copying entities with xdata between drawings

SRSDS
Advisor
Advisor

I monitor the ObjectAppended event for ObjIDs that have been pasted that contain xdata so that I can update the entities with new data. This works fine within the same drawing.

    Public Shared Sub callback_ObjectAppended(ByVal sender As Object, ByVal e As ObjectEventArgs)
        If CopyEvent Or MirrorEvent Or PasteEvent Or RotateEvent Then
            If e.DBObject.GetXDataForApplication(AppName) IsNot Nothing Then
                Dim myXdata As Array = e.DBObject.GetXDataForApplication(AppName).AsArray
                If Not CloneIDDict.Contains(e.DBObject.ObjectId) Then
                    CloneIDDict.Add(e.DBObject.ObjectId)
                End If
            End If
        End If
    End Sub

I can't figure out what is happening when I paste between drawings though.

The number of appended ObjIDs is double the number copied and is causing some strange problems of invisible entities that contain xdata.

Is there some explanation of why this might be? Or a better way of doing what I am trying to do? 

 

 

0 Likes
Accepted solutions (1)
1,151 Views
5 Replies
Replies (5)
Message 2 of 6

_gile
Consultant
Consultant

Hi,

 

The clipborad is a Windows mechanism, not an AutoCAD one.

When you copy AutoCAD entities in the clipboard, AutoCAD does something similar to the WLOCK command, it stores the copied objects in a temporary dwg and when you paste these entites in the same or another drawing, AutoCAD inserts the temporary model space, explodes and purges this block reference this is the reason why the appended objects sequence looks like:

  1. BlockBegin
  2. BlockEnd
  3. BlockTableRecord
  4. Then, the sequence of copied entities within the block definition
  5. BlockReference
  6. Finally, the sequence of copied entites in the current block table record

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 6

_gile
Consultant
Consultant
Accepted solution

Here's a little sample to handle the PASTECLIP and PASTEORG commands.

The copied object are colored in red (10).

 

C#

using System;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;

namespace CatchPastedEntitiesSample
{
    public class Initialization : IExtensionApplication
    {
        DocumentCollection docMgr;
        ObjectIdCollection appendedIds;

        public void Initialize()
        {
            docMgr = Application.DocumentManager;
            appendedIds = new ObjectIdCollection();
            Application.Idle += OnIdle;
        }

        public void Terminate()
        { }

        private void OnIdle(object sender, EventArgs e)
        {
            var doc = docMgr.MdiActiveDocument;
            if (doc != null)
            {
                Application.Idle -= OnIdle;
                doc.CommandWillStart += Doc_CommandWillStart;
                docMgr.DocumentCreated += DocMgr_DocumentCreated;
            }
        }

        private void DocMgr_DocumentCreated(object sender, DocumentCollectionEventArgs e)
        {
            e.Document.CommandWillStart += Doc_CommandWillStart;
        }

        private void Doc_CommandWillStart(object sender, CommandEventArgs e)
        {
            if (e.GlobalCommandName == "PASTECLIP" || e.GlobalCommandName == "PASTEORIG")
            {
                var doc = docMgr.MdiActiveDocument;
                appendedIds.Clear();
                doc.Database.ObjectAppended += Database_ObjectAppended;
                doc.CommandCancelled += Doc_CommandFailedOrCancelled;
                doc.CommandFailed += Doc_CommandFailedOrCancelled;
                doc.CommandEnded += Doc_CommandEnded;
            }
        }

        private void Database_ObjectAppended(object sender, ObjectEventArgs e)
        {
            var dbObj = e.DBObject;
            if (dbObj is Entity && dbObj.OwnerId == dbObj.Database.CurrentSpaceId)
                appendedIds.Add(e.DBObject.ObjectId);
        }

        private void Doc_CommandEnded(object sender, CommandEventArgs e)
        {
            UnRegisterHandlers();
            using (var tr = new OpenCloseTransaction())
            {
                foreach (ObjectId id in appendedIds)
                {
                    if (!id.IsErased)
                    {
                        var ent = (Entity)tr.GetObject(id, OpenMode.ForWrite);
                        ent.ColorIndex = 10;
                    }
                }
                tr.Commit();
            }
        }

        private void Doc_CommandFailedOrCancelled(object sender, CommandEventArgs e)
        {
            UnRegisterHandlers();
        }

        private void UnRegisterHandlers()
        {
            var doc = docMgr.MdiActiveDocument;
            doc.CommandCancelled -= Doc_CommandFailedOrCancelled;
            doc.CommandFailed -= Doc_CommandFailedOrCancelled;
            doc.CommandEnded -= Doc_CommandEnded;
            doc.Database.ObjectAppended -= Database_ObjectAppended;
        }
    }
}

VB

Imports System
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Runtime


Public Class Initialization
    Implements IExtensionApplication

    Private docMgr As DocumentCollection
    Private appendedIds As ObjectIdCollection

    Public Sub Initialize() Implements IExtensionApplication.Initialize
        docMgr = Application.DocumentManager
        appendedIds = New ObjectIdCollection()
        AddHandler Application.Idle, AddressOf OnIdle
    End Sub

    Public Sub Terminate() Implements IExtensionApplication.Terminate
    End Sub

    Private Sub OnIdle(ByVal sender As Object, ByVal e As EventArgs)
        Dim doc = docMgr.MdiActiveDocument

        If doc IsNot Nothing Then
            RemoveHandler Application.Idle, AddressOf OnIdle
            AddHandler doc.CommandWillStart, AddressOf Doc_CommandWillStart
            AddHandler docMgr.DocumentCreated, AddressOf DocMgr_DocumentCreated
        End If
    End Sub

    Private Sub DocMgr_DocumentCreated(ByVal sender As Object, ByVal e As DocumentCollectionEventArgs)
        AddHandler e.Document.CommandWillStart, AddressOf Doc_CommandWillStart
    End Sub

    Private Sub Doc_CommandWillStart(ByVal sender As Object, ByVal e As CommandEventArgs)
        If e.GlobalCommandName = "PASTECLIP" OrElse e.GlobalCommandName = "PASTEORIG" Then
            Dim doc = docMgr.MdiActiveDocument
            appendedIds.Clear()
            AddHandler doc.Database.ObjectAppended, AddressOf Database_ObjectAppended
            AddHandler doc.CommandCancelled, AddressOf Doc_CommandFailedOrCancelled
            AddHandler doc.CommandFailed, AddressOf Doc_CommandFailedOrCancelled
            AddHandler doc.CommandEnded, AddressOf Doc_CommandEnded
        End If
    End Sub

    Private Sub Database_ObjectAppended(ByVal sender As Object, ByVal e As ObjectEventArgs)
        Dim dbObj = e.DBObject
        If TypeOf dbObj Is Entity AndAlso dbObj.OwnerId = dbObj.Database.CurrentSpaceId Then appendedIds.Add(e.DBObject.ObjectId)
    End Sub

    Private Sub Doc_CommandEnded(ByVal sender As Object, ByVal e As CommandEventArgs)
        UnRegisterHandlers()

        Using tr = New OpenCloseTransaction()

            For Each id As ObjectId In appendedIds

                If Not id.IsErased Then
                    Dim ent = CType(tr.GetObject(id, OpenMode.ForWrite), Entity)
                    ent.ColorIndex = 10
                End If
            Next

            tr.Commit()
        End Using
    End Sub

    Private Sub Doc_CommandFailedOrCancelled(ByVal sender As Object, ByVal e As CommandEventArgs)
        UnRegisterHandlers()
    End Sub

    Private Sub UnRegisterHandlers()
        Dim doc = docMgr.MdiActiveDocument
        RemoveHandler doc.CommandCancelled, AddressOf Doc_CommandFailedOrCancelled
        RemoveHandler doc.CommandFailed, AddressOf Doc_CommandFailedOrCancelled
        RemoveHandler doc.CommandEnded, AddressOf Doc_CommandEnded
        RemoveHandler doc.Database.ObjectAppended, AddressOf Database_ObjectAppended
    End Sub
End Class


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 6

kerry_w_brown
Advisor
Advisor

Nice sample @_gile .

 

 


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
0 Likes
Message 5 of 6

SRSDS
Advisor
Advisor

Gile,

Thank you so much for taking the time to write that.

Answers my question, solves several workarounds that I've needed to add, but most importantly your sample probably also explains why my app is crashing. I currently have all the eventhandlers running concurrently (15 of them on every open drawing). You seem to be very careful to add them only when needed and remove after they have been triggered.

 

Going to take me a while to restructure but I'll mark it as solved.

Thank you!

0 Likes
Message 6 of 6

_gile
Consultant
Consultant

You're welcome, I'm glad it helps you as much as you say.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes