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
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.
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?
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
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
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
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.
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 work
[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
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
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(); } } }
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
@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;
@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.
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