AutoCAD.NET二次開發:擴展數據之XData


結果緩存——ResultBuffer

  結果緩存即 Autodesk.AutoCAD.DatabaseServices.ResultBuffer 類型,使用 ResultBuffer 對象時需要提供一個數據對,每個數據對包含一個數據類型描述和一個值,這些數據對是 Autodesk.AutoCAD.DatabaseServices.TypedValue 類的實例。

  TypedValue.TypeCode 屬性是一個16位整型數據,它指明 TypedValue.Value 屬性的數據類型,可接受的 TypeCode 值取決於 ResultBuffer 實例的使用范圍,例如,適用於擴展記錄定義的 TypeCode 值就不適合於 XData。而Autodesk.AutoCAD.DatabaseServices.DxfCode 枚舉類型定義的碼值則描述了 ResultBuffer 可能的數據類型。

  TypedValue.Value 屬性是一個 System.Object 的實例,它可以包含任何類型的數據;但是,Value 的數據必須符合由 TypeCode 指明的類型。

  創建 ResultBuffer 方法有兩種:

  一種是使用構造函數創建,即在聲明 ResultBuffer 時將一個 TypedValue 作用參數傳給 ResultBuffer:

ResultBuffer  resBuf = new ResultBuffer(new TypedValue((int)DxfCode.Text, "我的擴展數據"));

  另一種是使用 ResultBuffer.Add() 方法來添加 TypedValue,可以添加多個TypedValue,但總數據大小不能超過128K:

ResultBuffer resBuf = new ResultBuffer (); 
resBuf.Add(new TypedValue ((int)DxfCode.Text, "我的擴展數據")); 
resBuf.Add(new TypedValue ((int)DxfCode.Real, 20.0)); 
resBuf.Add(new TypedValue((int)DxfCode.Int32, 5));

 

擴展數據——XData

  AutoCAD 數據庫對象都可以靈活的添加一定數量的自定義數據,供開發者使用,這些數據的含義由開發者自行解釋,AutoCAD 只維護這些數據而不管其具體的含義,這些數據被稱為擴展數據(XData),擴展數據以結果緩存形式附加在實體上,因此,能夠有效的利用存儲空間,對於添加輕量的數據非常方便的。

  可以通過實體 DBObject 類及其派生類的 XData 屬性獲取或設置擴展數據。實體的擴展數據由應用程序創建, 附着在實體的擴展數據可以包含一個或多個組。每一組均以一個互不相同的注冊應用程序名開頭,擴展數據 XData 所支持的TypedValue.TypeCode 屬性值(DXF 組碼)只能采用 1000~1071 之間的組碼值,不同組碼對應不同類型的信息,各個組碼的說明如下表所示:

DXF 組碼值  擴展數據內容
1000~1009

字符串 (最多不超過 255 個字
符)

1001  Xdata 的應用程序名
1002  Xdata 的控制字符串
1003 圖層名
1004 二進制數據
1005 數據庫對象句柄
1010~1059  浮點數
1010,1020,1030  三維點(x, y , z)
1011,1021,1031  三維空間位置
1012,1022,1032  三維空間距離
1013,1023,1033  三維空間方向
1040  Xdata 中的浮點數
1041  Xdata 中的距離值
1042 Xdata 中的比例系數
1060~1070  16 位整數
1071  32 位整數

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  由於每個數據庫對象可以附加多個應用程序的數據,所以在 ResultBuffer 中,應用程序名是每段擴展數據的第一個數據,其后的結果緩沖數據都歸此應用程序名所有。(也可以使用其他的特殊標識作為第一個數據,總之目的是為了便於區分,方便后期查詢此擴展數據)

  AutoCAD 將注冊的應用程序名稱保存於數據庫中的 RegAppTable 表中,在使用之前,必須首先檢測是否已經存在 RegAppTable 表中,如果沒有則需要注冊,也就是創建一個 RegAppTableRecord 表記錄, 注冊程序的名字最長可達 31 個字符,以下代碼完成 RegAppTableRecord 表記錄的創建:

RegAppTable appTbl = trans.GetObject(db.RegAppTableId, OpenMode.ForWrite) as RegAppTable ; 
if (!appTbl.Has("MyAppName")) 
{ 
  RegAppTableRecord appTblRcd = new RegAppTableRecord(); 
  appTblRcd.Name ="MyAppName"; 
  appTbl.Add(appTblRcd); 
  trans.AddNewlyCreatedDBObject(appTblRcd, true); 
} 

  

  添加擴展數據到數據庫對象上,首先需要獲取數據注冊應用程序名,然后通過 DBObject 類及其派生類的 XData 屬性設置擴展數據,如以下代碼所示: 

public void AddXData() 
{ 
  Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; 
  ed.WriteMessage("添加擴充數據 XDATA\n"); 
  PromptEntityOptions entOps = new PromptEntityOptions("選擇實體對象"); 
  PromptEntityResult entRes; 
  entRes = ed.GetEntity(entOps); 
  if (entRes.Status != PromptStatus.OK) 
  { 
    ed.WriteMessage("選擇對象失敗,退出"); 
    return; 
  } 
  ObjectId objId = entRes.ObjectId; 
  Database db = HostApplicationServices.WorkingDatabase; 
  using (Transaction trans = db.TransactionManager.StartTransaction()) 
  { 
    Entity ent = trans.GetObject(objId, OpenMode.ForWrite) as Entity ; 
    ent.ColorIndex =1; 
    RegAppTable appTbl = trans.GetObject(db.RegAppTableId, OpenMode.ForWrite) as RegAppTable ; 
    if (!appTbl.Has("MyAppName")) 
    { 
      RegAppTableRecord appTblRcd = new 
      RegAppTableRecord(); 
      appTblRcd.Name ="MyAppName"; 
      appTbl.Add(appTblRcd); 
      trans.AddNewlyCreatedDBObject(appTblRcd, true); 
    } 
    ResultBuffer resBuf = new ResultBuffer();
    resBuf.Add(new TypedValue(1001, "我的擴展數據應用程序"));
    resBuf.Add(new TypedValue(1000, "作者:王"));
    ent.XData = resBuf; 
    trans.Commit(); 
  } 
} 

  從指定的對象返回所附着的擴展數據也需要通過 DBObject 類及其派生類的XData 屬性,返回的結果為 ResultBuffer,可以用.AsArray()方法將其轉換為一個TypedValue[]數組,或者借助遍歷器 IEnumerator(在 System.Collections 命名空間中),同時根據 DXF 的組碼值判斷所添加的數據,這些數據的含義由開發者自行解釋。

  使用自帶方法轉為數組:

TypedValue[] tvs = rb.AsArray();

  使用IEnumerator遍歷:

public void GETXDATA() 
{ 
  Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; 
  ed.WriteMessage("獲取擴充數據 XDATA\n"); 
  PromptEntityOptions entOps = new PromptEntityOptions("選擇實體對象"); 
  PromptEntityResult entRes = ed.GetEntity(pr); 
  if (entRes.Status != PromptStatus.OK) 
  { 
    ed.WriteMessage("選擇對象失敗,退出"); 
    return; 
  } 
  Database db = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database; 
  using (Transaction tr = db.TransactionManager.StartTransaction()) 
  { 
    Entity ent = (Entity)tr.GetObject(res.ObjectId, OpenMode.ForRead); 
    ResultBuffer resBuf = ent.XData; 
    if (resBuf ! = null) 
    { 
      IEnumerator iter = resBuf.GetEnumerator(); 
      while (iter.MoveNext()) 
      { 
        TypedValue tmpVal = (TypedValue)iter.Current; 
        ed.WriteMessage(tmpVal.TypeCode.ToString() + ":"); 
        ed.WriteMessage(tmpVal.Value.ToString() +"\n"); 
      } 
    } 
  } 
} 

  也可以將擴展數據讀取到更常用的List<T>中,參考代碼如下:

public List<System.Object> GetXDataList(Entity ent)
{
  Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
  List<System.Object> objs = new List<System.Object>();
  Database db = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
  using (Transaction trans = db.TransactionManager.StartTransaction())
  {
    ent = (Entity)trans.GetObject(ent.ObjectId, OpenMode.ForRead);
    ResultBuffer resBuf = ent.XData;
    if (resBuf != null)
    {
      System.Collections.IEnumerator itor = resBuf.GetEnumerator();
      while (itor.MoveNext())
      {
        TypedValue tmpVal = (TypedValue)itor.Current;
        objs.Add(tmpVal.Value);
          }
    }
    trans.Commit();   }
  return objs; }

 

  要注意的是,XData是比較特殊的,給實體添加擴展數據,是這樣的:

ResultBuffer rb = new ResultBuffer(
  new TypedValue[]{
        new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
         new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123")
   });
line.XData = rb;

  但是這里雖然是用等號賦值的,但是它並不一定會覆蓋舊的擴展數據,一個實體,只有一個XData屬性,但是里面可以記錄多個不同應用程序名的擴展數據。

  每次用“=”給實體的XData賦值時,如果XData里還沒有這個應用程序的擴展數據,那么新賦的這些值,會被添加到原有的XData結尾去,比如上面已經給line對象添加了應用程序“abc”的擴展數據,這個時候讀取line的XData,其內容應該是這樣的:

new TypedValue[]{
    new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
    new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123")
}

  這時候,再給line添加一個新的應用程序"lc"的擴展數據:

ResultBuffer rb1 = new ResultBuffer(
new TypedValue[]{
  new TypedValue((int)DxfCode.ExtendedDataRegAppName,"lc"),
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"0")
});
line.XData = rb1;

  此時,如果再讀取line的XData,那么結果就會是:

new TypedValue[]{
  new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123"),
  new TypedValue((int)DxfCode.ExtendedDataRegAppName,"lc"),
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"0")
}

  這樣的話,那如果同一個實體如果有多個應用程序的擴展數據,那我怎么取其中某一個應用程序的擴展數據呢?

  答案是使用:GetXDataForApplication方法,該方法的參數就是應用程序名,比如:

ResultBuffer res = line.GetXDataForApplication("abc");

這樣取到的結果就是:
new TypedValue[]{
  new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123")
}

 

  如果要修改擴展數據,只需要對XData重新賦值就行,比如現在我們修改應用程序abc的擴展數據:

line.XData = new ResultBuffer(
new TypedValue[]{
  new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"1231"),
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"1")
});

//對XData重新賦值時,如果XData里已經有了abc的擴展數據,那么會把原有的abc的擴展數據替換掉,如果現在還沒有abc的擴展數據,那么就會在XData結尾處添加上新的擴展數據。

 

  如果要刪除擴展數據,操作方式如下:

//刪除應用程序abc的擴展數據,只需要進行一個這樣的賦值,新值里只添加一個應用程序名,不添加其他值,這樣XData中,原有的abc的擴展數據就會被刪除
line.XData = new ResultBuffer(
  new TypedValue[]{
  new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc")
});

  注意:盡量不要直接刪除已經在RegAppTable里注冊的應用程序名,如果圖紙上的實體上添加了此應用程序的擴展數據,那么擴展數據中對應的應用程序名會被刪掉,但它下面對應的其他數據值並不會被刪除,有可能會引發問題,例如:

//刪除應用程序abc在RegAppTable里的記錄
RegAppTable rat = (RegAppTable)trans.GetObject(db.RegAppTableId, OpenMode.ForWrite);
if (!rat.Has("abc"))
{
  RegAppTableRecord ratr = (RegAppTableRecord)rat["abc"].GetObject(OpenMode.ForWrite);
  ratr.Erase();
}

//這時,讀取line的XData,其內容會是這樣(假設我們上一步,沒有刪除line中abc的擴展數據)
new TypedValue[]{
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123"),
  new TypedValue((int)DxfCode.ExtendedDataRegAppName,"lc"),
  new TypedValue((int)DxfCode.ExtendedDataAsciiString,"0")
}

  所以,個人認為,在刪除RegAppTable中的已注冊的應用程序名時,應先用過濾選擇器選擇出添加了此應用程序擴展數據的實體,然后將它們的擴展數據刪除,然后再去刪除RegAppTable中的應用程序注冊信息。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM