.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to edit and update Xdata for selected object

14 REPLIES 14
Reply
Message 1 of 15
alistairc
8265 Views, 14 Replies

How to edit and update Xdata for selected object

Hi Guys,

I am new to VB.net working with AutoCAD 2010

 

What I want to do is for selected object I need to get the XData under a certain application name, edit it and update back to the object.

            For Each objID As ObjectId In objIDs

                objFixture = trans.GetObject(objID, OpenMode.ForWrite)
                xdataFixture = objFixture.GetXDataForApplication(STR_XDATA_FIXTURE)
                Dim varFixXData() As TypedValue = xdataFixture.AsArray
                If UBound(varFixXData) <> MAX_INDEX_XDATA_FIXTURE Then
                    ReDim Preserve varFixXData(MAX_INDEX_XDATA_FIXTURE)
                End If
                varFixXData(INDEX_XDATA_FIXTURE_ZONE_HANDLE) = New TypedValue(1000, "hello")
                Dim rbNewFixXData As ResultBuffer = New ResultBuffer(varFixXData)
                objFixture.XData = rbNewFixXData
                rbNewFixXData.Dispose()
                xdataFixture.Dispose()
            Next
            trans.Commit()

 The code won't throw any exception. just didn't update the object. I save the drawing and open again the XData is still the same as it was

 

Any idea or suggestions?

Thanks

14 REPLIES 14
Message 2 of 15
caddzone
in reply to: alistairc

When you set the XData property, the first item in the ResultBuffer

must be the Xdata application name (TypeCode = 1001).

 

I don't recall if that is returned by GetXDataForApplication(), so if it

isn't in the ResultBuffer returned by that API, you will need to insert it.



AcadXTabs for AutoCAD
Supporting AutoCAD 2000-2011


Message 3 of 15
alistairc
in reply to: caddzone

Thanks for the reply, It is return ed by 

GetXDataForApplication

 

I put result into watch, it contains the hold xdata including xdata header

 

Any other reason?

Message 4 of 15
Jeffrey_H
in reply to: alistairc

Do you know schema or how many vaules are under that AppName and which order they are in does not matter if their is other appNames stored on the object.

 

This is a simple example that will change or repalce value if you have more than one value stored you could pass it to a list replace the value and add back to object.

 

I would wait to see if Tony  replies back because he will probably have a better way of doing it

 

 Public Const AppName As String = "AppName"
    Dim bool As Boolean = False
    <CommandMethod("ADDXDATA")> _
      Public Sub AddXdata()
        Dim db As Database = DocumentManager.MdiActiveDocument.Database
        Dim ed As Editor = DocumentManager.MdiActiveDocument.Editor
        Dim peo As New PromptEntityOptions("Select")
        Dim per As PromptEntityResult = ed.GetEntity(peo)
        Using tr As Transaction = db.TransactionManager.StartTransaction
            Dim regAppTbl As RegAppTable = tr.GetObject(db.RegAppTableId, OpenMode.ForRead)
            If regAppTbl.Has(AppName) = False Then
                Dim regAppRec As New RegAppTableRecord
                regAppTbl.UpgradeOpen()
                regAppRec.Name = AppName
                regAppTbl.Add(regAppRec)
                tr.AddNewlyCreatedDBObject(regAppRec, True)
            End If
            Dim ent As Entity = tr.GetObject(per.ObjectId, OpenMode.ForWrite)
            Dim value As String

            If bool Then
                value = "New"
            Else
                value = "Old"
            End If
            ent.XData = New ResultBuffer(New TypedValue(DxfCode.ExtendedDataRegAppName, AppName), _
                                            New TypedValue(1000, value))
            Dim rb As ResultBuffer = GetXData(ent.ObjectId, AppName)
            For Each typV As TypedValue In rb
                MsgBox(typV.Value.ToString)
            Next
            bool = Not bool
            tr.Commit()
        End Using
    End Sub

 

 

 

You can also find your answers @ TheSwamp
Message 5 of 15
alistairc
in reply to: Jeffrey_H

thanks for reply

 

the XData array index from 0 to 12.

 

the first one varData(0) is the Header (1001, "header name ") and all the rest are string type (1000,"string value")

 

the code you gave is to set a new xdata for one object not change and update, but I will try this later.

 

Thanks again

Message 6 of 15
Jeffrey_H
in reply to: alistairc

Sorry the previous code will crash I forgot to post this function with it

 I might be missing something but if you run addXdata on same entitiy it will change each time from new to old and back to new and so on.

 

  Function GetXData(ByVal entID As ObjectId, ByVal AppName As String) As ResultBuffer
        Using tr As Transaction = entID.Database.TransactionManager.StartTransaction
            Dim ent As Entity = entID.GetObject(OpenMode.ForRead)
            Dim rb As ResultBuffer = ent.GetXDataForApplication(AppName)
            Return rb
        End Using
    End Function

 

You can also find your answers @ TheSwamp
Message 7 of 15
chiefbraincloud
in reply to: alistairc


About this part:

 

If UBound(varFixXData) <> MAX_INDEX_XDATA_FIXTURE Then
   ReDim Preserve varFixXData(MAX_INDEX_XDATA_FIXTURE)
End If
varFixXData(INDEX_XDATA_FIXTURE_ZONE_HANDLE) = New TypedValue(1000, "hello")

 

If that redim Preserve statement ever makes varFixXData larger by more than one, (OR) if it makes varFixXData larger by one AND MAX_INDEX.... is not equal to INDEX_XDATA....  Then you will have one or more empty TypedValues at the end of your array.

 

I would expect that to throw some kind of error, but I haven't tried it.

 

Then you said ' I save the drawing and open again the XData is still the same as it was':

 

Try checking the values of the xdata immediately after you change them. You could use this lisp code to print all entity data including all XData from a selected entity.  You can put the AppName in place of the * and it will only print your XData.

(setq e (car (entsel)) ent (entget e '("*")))

 

If it is correct immediately after you run the function, then another routine must be resetting it when you open.

 

Other than that, I have similar code that works fine, and I don't see a glaring problem.

 

Dave O.                                                                  Sig-Logos32.png
Message 8 of 15
alistairc
in reply to: chiefbraincloud

Thanks for replies but I still can't do it.

 

I try to get the XData straight after and there is no change.

 

I manage to use the VB6 way to update XData

 

objFix = m_objDrawing.HandleToObject(strFixHandle)

 

Dim objFix As Autodesk.AutoCAD.Interop.Common.AcadObjectDim varType As Object, varValue As Object

objFix.GetXData(STR_XDATA_FIXTURE, varType, varValue)

varValue(INDEX_XDATA_FIXTURE_ZONE_HANDLE) = strZoneHandle

objFix.SetXData(varType, varValue)

 

Dim varType1 As Object, varValue1 As Object

objFix.GetXData(STR_XDATA_FIXTURE, varType1, varValue1)

 

I got no idea why .net way doesn't workSmiley Sad

 

Message 9 of 15
xsfhlzh
in reply to: alistairc

        [CommandMethod("tt4")]
        public void test24()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            var resEnt = ed.GetEntity("Select a Entity");
            if (resEnt.Status == PromptStatus.OK)
            {

                using (var tr = db.TransactionManager.StartTransaction())
                {

                    Entity ent = tr.GetObject(resEnt.ObjectId, OpenMode.ForWrite) as Entity;
                    var rb = ent.GetXDataForApplication("MyTestApp");

                    if (rb == null)
                    {
                        var rat = tr.GetObject(db.RegAppTableId, OpenMode.ForWrite) as RegAppTable;
                        if (!rat.Has("MyTestApp"))
                        {
                            var ratr = new RegAppTableRecord();
                            ratr.Name = "MyTestApp";
                            rat.Add(ratr);
                            tr.AddNewlyCreatedDBObject(ratr, true);
                        }

                        ent.XData = new ResultList { { 1001, "MyTestApp" }, { 1000, "value1" } };
                    }
                    else
                    {
                        List<TypedValue> values = rb.Cast<TypedValue>().ToList();
                        values.Add(new TypedValue(1000, "value" + values.Count.ToString()));
                        ent.XData = new ResultBuffer(values.ToArray());
                    }

                    tr.Commit();
                }
            }
        }

 Just a example

Message 10 of 15
alistairc
in reply to: xsfhlzh

Thanks for reply

 

I think I found where is the problem.  I use ed.Getselection

 

After that I try loop all objectID to update Xdata for each selected object

if I dim objFixture as Entity AutoCAD will throw exception when I try to getobject from tans. More than that this exception kills AutoCAD even I catch it.

if I use your sample code which is ed.GetEntity I can dim objFixture as Entity then NO problem

I have to dim objFixture as DBObject then the xdata update doesn't work.

 

 

I have put all my function code here.

 

please help me I stucked here for a couple of days now

 

Thanks very much

    Public Sub AssignFixtureToZone()
        Dim ed As Editor = acApp.DocumentManager.MdiActiveDocument.Editor
        Dim trans As Transaction = acApp.DocumentManager.MdiActiveDocument.Database.TransactionManager.StartTransaction
        Try


            Dim varData(0) As TypedValue
            ReDim varData(0)
            varData(0) = New TypedValue(1001, STR_XDATA_FIXTURE)

            '--Select Fixture
            Dim varFilterFixture As New SelectionFilter(varData)
            Dim PptSelection As New PromptSelectionOptions
            PptSelection.MessageForAdding = "Please select fixtures"
            Dim psrFixture As PromptSelectionResult = ed.GetSelection(PptSelection, varFilterFixture)
            If psrFixture.Status = PromptStatus.OK Then
                MessageBox.Show("I am a temp testing version!!!")
            Else
                Exit Try
            End If
            Dim objIDs() As ObjectId = psrFixture.Value.GetObjectIds
            Dim xdataFixture As ResultBuffer
            Dim rb As ResultBuffer
            Dim objFixture As Entity
            For Each objID As ObjectId In objIDs

                objFixture = trans.GetObject(objID, OpenMode.ForWrite)
                Dim rbOld As ResultBuffer = objFixture.GetXDataForApplication(STR_XDATA_FIXTURE)
                Dim tvOld() As TypedValue = rbOld.AsArray
                If tvOld.GetUpperBound(0) <> MAX_INDEX_XDATA_FIXTURE Then
                    ReDim Preserve tvOld(MAX_INDEX_XDATA_FIXTURE)
                End If
                tvOld(INDEX_XDATA_FIXTURE_ZONE_HANDLE) = New TypedValue(1000, "I need Here")

                rb = New ResultBuffer(tvOld)
                objFixture.XData = rb
                rb.Dispose()
                rbOld.Dispose()
            Next
            trans.Commit()
            trans.Dispose()
        Catch ex As Exception
            ed.WriteMessage("exception " + ex.InnerException.ToString)
        Finally
            trans.Dispose()
        End Try

    End Sub

 

Message 11 of 15
xsfhlzh
in reply to: alistairc

So, try this code

 

        [CommandMethod("tt4")]
        public void test24()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            var resSel = ed.GetSelection(new ResultList { {0, "Line"}});
            if (resSel.Status == PromptStatus.OK)
            {

                using (var tr = db.TransactionManager.StartTransaction())
                {

                    foreach (ObjectId id in resSel.Value.GetObjectIds())
                    {
                        Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;
                        var rb = ent.GetXDataForApplication("MyTestApp");

                        if (rb == null)
                        {
                            var rat = tr.GetObject(db.RegAppTableId, OpenMode.ForWrite) as RegAppTable;
                            if (!rat.Has("MyTestApp"))
                            {
                                var ratr = new RegAppTableRecord();
                                ratr.Name = "MyTestApp";
                                rat.Add(ratr);
                                tr.AddNewlyCreatedDBObject(ratr, true);
                            }

                            ent.XData =
                                new ResultList 
                            { 
                                { 1001, "MyTestApp" },
                                { 1000, "value1" } 
                            };
                        }
                        else
                        {
                            List<TypedValue> values = rb.Cast<TypedValue>().ToList();
                            values.Add(new TypedValue(1000, "value" + values.Count.ToString()));
                            ent.XData = new ResultBuffer(values.ToArray());
                        }
                    }

                    tr.Commit();
                }
            }
        }

 

Message 12 of 15
alistairc
in reply to: alistairc

After some more investigations

 

I include one more namespace

Imports Autodesk.AutoCAD.Runtime

 

then code stoped here

objFixture = trans.GetObject(objID, OpenMode.ForRead)

 

with error

Operation is not valid due to the current state of the object.

 

Any help

 

Thanks

 

Message 13 of 15
alistairc
in reply to: xsfhlzh


@xsfhlzh wrote:

So, try this code

 

        [CommandMethod("tt4")]
        public void test24()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;

            var resSel = ed.GetSelection(new ResultList { {0, "Line"}});
            if (resSel.Status == PromptStatus.OK)
            {

                using (var tr = db.TransactionManager.StartTransaction())
                {

                    foreach (ObjectId id in resSel.Value.GetObjectIds())
                    {
                        Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;
                        var rb = ent.GetXDataForApplication("MyTestApp");

                        if (rb == null)
                        {
                            var rat = tr.GetObject(db.RegAppTableId, OpenMode.ForWrite) as RegAppTable;
                            if (!rat.Has("MyTestApp"))
                            {
                                var ratr = new RegAppTableRecord();
                                ratr.Name = "MyTestApp";
                                rat.Add(ratr);
                                tr.AddNewlyCreatedDBObject(ratr, true);
                            }

                            ent.XData =
                                new ResultList 
                            { 
                                { 1001, "MyTestApp" },
                                { 1000, "value1" } 
                            };
                        }
                        else
                        {
                            List<TypedValue> values = rb.Cast<TypedValue>().ToList();
                            values.Add(new TypedValue(1000, "value" + values.Count.ToString()));
                            ent.XData = new ResultBuffer(values.ToArray());
                        }
                    }

                    tr.Commit();
                }
            }
        }

 


This won't work on me

as  I won't be able to pass this line

Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;

Message 14 of 15
chiefbraincloud
in reply to: alistairc


@alistairc wrote:

 

This won't work on me

as  I won't be able to pass this line

Entity ent = tr.GetObject(id, OpenMode.ForWrite) as Entity;


GetXDataForApplication is a member of DBObject, so you don't need to cast to Entity.  At least In AutoCAD 2010, I don't remember that changing since I switched over to .NET. 

 

 

Dave O.                                                                  Sig-Logos32.png
Message 15 of 15
xsfhlzh
in reply to: alistairc

I test it use VB thought cad2010,work well

 

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.DatabaseServices

Imports TlsCad.Collections

Public Class Class1

    <CommandMethod("VT1")> _
    Public Shared Sub Test1()

        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim ed As Editor = doc.Editor
        Dim db As Database = doc.Database

        Dim rl As ResultList = New ResultList()
        rl.Add(0, "Line")
        Dim resSel = ed.GetSelection(rl)

        Using tr As Transaction = db.TransactionManager.StartTransaction

            Dim rat As RegAppTable = tr.GetObject(db.RegAppTableId, OpenMode.ForWrite)
            If Not rat.Has("MyTestApp") Then
                Dim ratr As New RegAppTableRecord()
                ratr.Name = "MyTestApp"
                rat.Add(ratr)
                tr.AddNewlyCreatedDBObject(ratr, True)
            End If

            For Each id In resSel.Value.GetObjectIds()

                Dim ent As Entity = tr.GetObject(id, OpenMode.ForWrite)
                Dim rb As ResultBuffer = ent.GetXDataForApplication("MyTestApp")

                If rb Is Nothing Then
                    rl = New ResultList()
                    rl.Add(1001, "MyTestApp")
                    rl.Add(1000, "value1")
                    ent.XData = rl
                Else
                    Dim values As New List(Of TypedValue)(rb.AsArray())
                    values.Add(New TypedValue(1000, "value" + values.Count.ToString()))
                    ent.XData = New ResultBuffer(values.ToArray())
                End If
            Next
            tr.Commit()
        End Using
    End Sub
End Class

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost