AutoCAD中的擴展字典及擴展記錄(C#)


在學習CAD擴展記錄的過程中,遇到了一些問題,也積累了一些經驗,現在給大家分享一些我的學習心得。在學習擴展字典之前需要讀者了解cad的組碼,也就是DxfCode。感興趣的也可以了解一下擴展數據的相關內容(后面有時間也會分享一下,因為擴展數據、擴展字典和DxfCode組碼之間有密切的關系)。

一個CAD對象只能擁有一個擴展字典,而擴展字典下面可以包含多個擴展記錄。打個比方,可以這么理解,如果擴展字典相當於excel文件,那么一個擴展記錄就相當於excel中的一個表單sheet對象,擴展記錄中存儲的數據就相當於表單sheet中的數據。

使用擴展記錄可以向對象中保存一些屬性數據,以便后續提取之用,這是很有用的。比如說可以向一個多段線(代表一根管線,或是其他)中存儲一些施工方面的數據信息,例如施工標段、樁號范圍、施工完成時間等,以后再打開圖的時候,就知道這段管線是哪個施工單位施工的,什么時間完成的等等,便於查看和統計。CAD程序自身的屬性對話框是無法記錄這些信息的。

向對象添加擴展記錄一般分為三個步驟:

1 將添加的數據構成一個類

2 編寫擴展方法,包括擴展記錄的添加、讀取、刪除、修改

3 調用擴展方法進行操作

界面如下:

 

下面列出主要的代碼

1 將需要添加的數據構成一個類,主要包括施工標段、信息、樁號、完成時間等屬性

 1  public class XDataClass
 2     {
 3         public string BiaoDuan { get; set; }//施工標段
 4         public string Information { get; set; }//附加到對象上的信息
 5         public double StationStart { get; set; }//起始樁號
 6         public double StationEnd { get; set; }//終止樁號
 7         public double Length { get; private set; }//長度
 8         public DateTime OverTime { get; set; }//完成時間
 9         public string XRecordName { get; set; } //擴展記錄名稱
10         public XDataClass() { }
11         public XDataClass(string xrecordName)
12         {
13             XRecordName = xrecordName;
14         }
15         /// <summary>
16         /// 將擴展數據實體類轉化成typevaluelist類型
17         /// </summary>
18         /// <param name="xdataClass"></param>
19         /// <returns></returns>
20         public static TypedValueList ClassToTypeValueList(XDataClass xdataClass)
21         {
22             TypedValueList tvList = new TypedValueList
23             {
24                 {DxfCode.Text, xdataClass.BiaoDuan },
25                 {DxfCode.Text, xdataClass.Information },
26                 {DxfCode .Real ,xdataClass.StationStart  },
27                 {DxfCode.Real ,xdataClass .StationEnd  },
28                 {DxfCode.Text ,xdataClass .OverTime .ToString ("d") },
29                 {DxfCode.Text ,xdataClass.XRecordName  },
30             }; 
31             return tvList;
32         }
33         /// <summary>
34         /// 將typevaluelist類型的數據轉換成實體類
35         /// </summary>
36         /// <param name="list"></param>
37         /// <returns></returns>
38         public static XDataClass TypeValueListToClass(TypedValueList list)
39         {
40             XDataClass xdataClass = new XDataClass()
41             {
42                 BiaoDuan = list[0].Value.ToString(),
43                 Information = list[1].Value.ToString(),
44                 StationStart = Convert.ToDouble(list[2].Value),
45                 StationEnd = Convert.ToDouble(list[3].Value),
46                 OverTime = Convert.ToDateTime(list[4].Value),
47                 XRecordName = list[5].Value.ToString(),
48                 Length = Math.Abs(Convert.ToDouble(list[3].Value) - Convert.ToDouble(list[2].Value))
49             };
50             return xdataClass;
51         }
52     }

 

2  編寫擴展方法,包括擴展記錄的添加、讀取、刪除、修改

  1 #region 對象的擴展記錄的添加、刪除、修改
  2         /// <summary>
  3         ///  添加擴展記錄,如果沒有擴展字典,那就創建擴展字典
  4         /// </summary>
  5         /// <param name="objId">對象的objectid</param>
  6         /// <param name="xRecordSearchKey">擴展記錄名稱</param>
  7         /// <param name="values">擴展記錄的內容</param>
  8         /// <returns></returns>
  9         public static bool AddXRecordToObj(this ObjectId objId, string xRecordSearchKey, TypedValueList values)
 10         {
 11             //添加擴展記錄之前,先創建對象的擴展字典
 12             DBObject obj = objId.GetObject(OpenMode.ForRead);//以讀的方式打開
 13             if (obj.ExtensionDictionary.IsNull)//如果對象無擴展字典,那就給創建
 14             {
 15                 obj.UpgradeOpen();//切換對象為寫的狀態
 16                 obj.CreateExtensionDictionary();//為對象創建擴展字典,一個對象只能擁有一個擴展字典
 17                 obj.DowngradeOpen();//將對象切換為讀的狀態
 18             }
 19             //打開對象的擴展字典
 20             DBDictionary dict = obj.ExtensionDictionary.GetObject(OpenMode.ForRead) as DBDictionary;
 21             //如果擴展字典中已包含指定的擴展記錄對象  
 22             if (dict.Contains(xRecordSearchKey))
 23             {
 24                  return false;//如果包含有指定的擴展記錄,那就退出
 25             }
 26             else //若沒有包含擴展記錄,則創建一個
 27             {
 28                 Xrecord xrec = new Xrecord();//為對象創建一個擴展記錄 
 29                 xrec.Data = values;//指定擴展記錄的內容,這里用到了自定義類型轉換,TypedValueList-->ResultBuffer
 30                 dict.UpgradeOpen();//將擴展字典切換為寫的狀態,以便添加一個擴展記錄
 31                 ObjectId xrecId = dict.SetAt(xRecordSearchKey, xrec);//在擴展字典中加入新建的擴展記錄,並指定它的搜索關鍵字
 32                 objId.Database.TransactionManager.AddNewlyCreatedDBObject(xrec, true);
 33                 dict.DowngradeOpen();//將擴展字典切換為讀的狀態
 34                 return true; 
 35             }
 36         }
 37 
 38         /// <summary>
 39         /// 用於替換擴展字典中的整個一條擴展記錄
 40         /// </summary>
 41         /// <param name="objId">對象id</param>
 42         /// <param name="xRecordSearchKey">擴展記錄的名稱</param>
 43         /// <param name="values">擴展記錄的內容</param>
 44         public static bool ModObjXrecord(this ObjectId objId, string xRecordSearchKey, TypedValueList values)
 45         {
 46             DBObject obj = objId.GetObject(OpenMode.ForRead);//以讀的方式打開對象
 47             ObjectId dictId = obj.ExtensionDictionary;//獲取對象的擴展字典id
 48             if (dictId.IsNull)
 49             {
 50                 return false;//若對象沒有擴展字典,則返回 
 51             }
 52             //如果對象有擴展字典,則以讀的方式打開
 53             DBDictionary dict = dictId.GetObject(OpenMode.ForRead) as DBDictionary;
 54             if (!dict.Contains(xRecordSearchKey))
 55             {
 56                 return false;//如果擴展字典中沒有包含指定關鍵字的擴展記錄,則返回 ;
 57             }
 58             ObjectId xrecordId = dict.GetAt(xRecordSearchKey);//獲取擴展記錄的id
 59             Xrecord xrecord = xrecordId.GetObject(OpenMode.ForWrite) as Xrecord;
 60             xrecord.Data = values;//覆蓋原來的數據,因為values有了新的指向
 61             xrecord.DowngradeOpen();//將擴展記錄切換為讀的狀態
 62             return true;
 63         }
 64 
 65         /// <summary>
 66         /// 獲取對象的擴展字典中的擴展記錄
 67         /// </summary>
 68         /// <param name="objId">對象的id</param>
 69         /// <param name="xRecordSearchKey">擴展記錄名稱</param>
 70         /// <returns></returns>
 71         public static TypedValueList GetObjXrecord(this ObjectId objId, string xRecordSearchKey)
 72         {
 73             DBObject obj = objId.GetObject(OpenMode.ForRead);//以讀的方式打開對象
 74             ObjectId dictId = obj.ExtensionDictionary;//獲取對象的擴展字典的id
 75             if (dictId.IsNull)
 76             {
 77                 //MessageBox.Show("沒有擴展字典");
 78                 return null;//若對象沒有擴展字典,則返回null
 79             }
 80             DBDictionary dict = dictId.GetObject(OpenMode.ForRead) as DBDictionary;//獲取對象的擴展字典
 81             if (!dict.Contains(xRecordSearchKey))
 82             {
 83                 return null;//如果擴展字典中沒有包含指定關鍵字的擴展記錄,則返回null;
 84             }
 85             //先要獲取對象的擴展字典或圖形中的有名對象字典,然后才能在字典中獲取要查詢的擴展記錄
 86             ObjectId xrecordId = dict.GetAt(xRecordSearchKey);//獲取擴展記錄對象的id
 87             Xrecord xrecord = xrecordId.GetObject(OpenMode.ForRead) as Xrecord;//根據id獲取擴展記錄對象
 88             TypedValueList values = xrecord.Data;
 89             return values;//values 數組應該是有先后順序的
 90         }
 91 
 92         /// <summary>
 93         ///用於刪除對象擴展字典中的指定的擴展記錄
 94         /// </summary>
 95         /// <param name="objId">對象id</param>
 96         /// <param name="xRecordSearchKey"> 擴展記錄名稱</param>
 97         public static bool DelObjXrecord(this ObjectId objId, string xRecordSearchKey)
 98         {
 99             DBObject obj = objId.GetObject(OpenMode.ForRead);//以讀的方式打開對象
100             ObjectId dictId = obj.ExtensionDictionary;//獲取對象的擴展字典id
101             if (dictId.IsNull)
102             {
103                 return false;//若對象沒有擴展字典,則返回 
104             }
105             //如果對象有擴展字典,則以讀的方式打開
106             DBDictionary dict = dictId.GetObject(OpenMode.ForRead) as DBDictionary;
107             if (dict.Contains(xRecordSearchKey))//如果擴展字典中包含指定關鍵字的擴展記錄,則刪除;
108             {
109                 dict.UpgradeOpen();//切換為寫的狀態
110                 dict.Remove(xRecordSearchKey);//刪除擴展記錄
111                 dict.DowngradeOpen();//切換為讀的狀態
112             }
113             return true;
114         }
115         
116         /// <summary>
117         /// 刪除對象的擴展字典下的所有的擴展記錄
118         /// 2018年4月7日09:44:12
119         /// </summary>
120         /// <param name="objId"></param>
121         public static bool DelObjAllXrecords(this ObjectId objId)
122         {
123             DBObject obj = objId.GetObject(OpenMode.ForRead);//以讀的方式打開對象
124             ObjectId dictId = obj.ExtensionDictionary;//獲取對象的擴展字典id
125             if (dictId.IsNull)
126             {
127                 return false;//若對象沒有擴展字典,則返回 
128             }
129             //如果對象有擴展字典,則以讀的方式打開
130             DBDictionary dict = dictId.GetObject(OpenMode.ForWrite) as DBDictionary;
131             //獲取擴展字典下的所有擴展記錄名稱集合 Keys 
132 133             List<string> listKeys = new List<string>();
134             foreach (var item in dict)//獲取擴展字典中的所有條目,也就是所有的擴展記錄的key
135             {
136                 listKeys.Add(item.Key);
137             }
138             foreach (var key in listKeys)//根據key,刪除擴展字典中的每一個條目(也就是擴展記錄)
139             {
140                 dict.Remove(key);
141             }
142             dict.DowngradeOpen();//切換為讀的狀態 
143             return true;
144         }
145 
146 
147         /// <summary>
148         /// 刪除對象的擴展字典,因為每個對象只能擁有一個擴展字典,所以給定對象的objectID就好了
149         ///  2018年4月7日09:17:44 
150         /// </summary>
151         /// <param name="objId"></param>
152         public static bool DeleteObjExtensionDictionary(this ObjectId objId)
153         {
154             DBObject obj = objId.GetObject(OpenMode.ForRead);//以讀的方式打開對象
155             ObjectId dictId = obj.ExtensionDictionary;//獲取對象的擴展字典的ID
156             if (dictId.IsNull)
157             {
158                 return false;    //沒有擴展字典
159             }
160             //有擴展字典 161             obj.UpgradeOpen();//切換對象為寫的狀態
162 objId.DelObjAllXrecords(); //調用上面的方法,在刪除擴展字典之前要先刪除擴展記錄
163 obj.ReleaseExtensionDictionary();//移除對象的擴展字典,一個對象只能擁有一個擴展字典 164 obj.DowngradeOpen();//將對象切換為讀的狀態 165 return true; 166 } 167 #endregion

 

3調用擴展方法

  a 添加擴展記錄

 1  //btn  添加擴展記錄
 2         XDataClass PipeXdataClass = new XDataClass(Enum_XRcordName.pipe_whlkx.ToString());
 3         ObjectId selectedObjId = ObjectId.Null;
 4         private void btnAddXData_Click(object sender, EventArgs e)
 5         {
 6             if (CheckValue() == false)
 7             {
 8                 return;
 9             }
10             _instance.Hide();
11             Document doc = AcadApp.DocumentManager.MdiActiveDocument;
12             Database db = doc.Database;
13             Editor ed = doc.Editor; 
14             PromptEntityResult entityResult = ed.GetEntity("\n請選擇一個多段線對象");//單個拾取對象 
15             if (entityResult.Status != PromptStatus.OK)
16             {
17                 _instance.Show();
18                 return;
19             }
20             GetDataFromControls(PipeXdataClass);//私有函數,將控件中的數據填充到實體類中
21             //獲取對象的ID
22             ObjectId objId = entityResult.ObjectId; 
23             bool result = false;
24             using (DocumentLock docLock = doc.LockDocument())
25             using (Transaction trans = db.TransactionManager.StartTransaction())
26             {
27                 //將xdataCalss類型的數據轉換成一個typevalue型的列表
28                 TypedValueList values = XDataClass.ClassToTypeValueList(PipeXdataClass);
29                 result = objId.AddXRecordToObj(PipeXdataClass.XRecordName, values);
30                 trans.Commit();
31             }
32             if (result)
33             {
34                 ed.WriteMessage("\n對象的擴展數據添加成功!");
35             }
36             else
37             {
38                 ed.WriteMessage("\n對象已經有擴展數據");
39             }
40             _instance.Show();
41         }

  

  b 讀取擴展記錄 

 1 //btn 讀取擴展記錄
 2         private void btnReadXData_Click(object sender, EventArgs e)
 3         {
 4             _instance.Hide();
 5             ClearContent();//清空控件中的內容
 6             Document doc = AcadApp.DocumentManager.MdiActiveDocument;
 7             Database db = doc.Database;
 8             Editor ed = doc.Editor;
 9             //開始事務處理
10             using (DocumentLock docLock = doc.LockDocument())
11             using (Transaction trans = db.TransactionManager.StartTransaction())
12             {
13                 PromptEntityResult entityResult = ed.GetEntity("\n請選擇一個對象");//拾取單個對象
14                 if (entityResult.Status != PromptStatus.OK)
15                 {
16                     ed.WriteMessage("\n取消了選擇");
17                     _instance.Show();
18                     return;
19                 }
20                 //獲取對象的ID
21                 ObjectId objId = entityResult.ObjectId;
22                 TypedValueList list = objId.GetObjXrecord(PipeXdataClass.XRecordName);
23                 if (list is null)
24                 {
25                     ed.WriteMessage("\n該對象沒有擴展記錄");
26                     _instance.Show();
27                     return;
28                 }
29                 if (list.Count <= 0)
30                 {
31                     ed.WriteMessage("\n有擴展記錄,但是記錄為空");
32                     _instance.Show();
33                     return;
34                 }
35                 else
36                 {
37                     PipeXdataClass = XDataClass.TypeValueListToClass(list);
38                     SetDataToControls(PipeXdataClass);//向控件中填充數據
39                     ed.WriteMessage("\n對象擴展數據讀取成功");
40                     selectedObjId = objId;
41                 }
42             }
43             _instance.Show();
44         }

 

  c 刪除擴展記錄

 1         //btn 刪除
 2         private void btnDeleteXData_Click(object sender, EventArgs e)
 3         {
 4             _instance.Hide();
 5             Document doc = AcadApp.DocumentManager.MdiActiveDocument;
 6             Database db = doc.Database;
 7             Editor ed = doc.Editor;
 8             //開始事務處理
 9             using (DocumentLock docLock = doc.LockDocument())
10             using (Transaction trans = db.TransactionManager.StartTransaction())
11             {
14                 PromptSelectionResult ss1 = ed.GetSelection();//框選對象
15                 if (ss1.Status != PromptStatus.OK)
16                 {
17                     ed.WriteMessage("\n取消了選擇");
18                     _instance.Show();
19                     return;
20                 }
21                 //獲取對象的ID
22                 List<ObjectId> listObjIds = ss1.Value.GetObjectIds().ToList();
23                 int count = 0;
24                 listObjIds.ForEach(objId =>
25                 {
26                     if (objId.DeleteObjExtensionDictionary())
27                     {
28                         ed.WriteMessage("\n刪除成功");
29                         count++;
30                     }
31                 });
32                 //ObjectId objId = entityResult.ObjectId;
33                 //2018年4月7日09:50:35,經驗證,必須先刪除擴展字典下的所有的擴展記錄,才能刪除對象的擴展字典
34                 //否則會出現錯誤:eContainerNotEmpty ,容器不為空
35                 //objId.DelObjAllXrecords();
36                 //objId.DeleteObjExtensionDictionary();
37                 trans.Commit();
38                 ed.WriteMessage("\n操作完成,總共刪除{0}個擴展記錄", count);
39             } 
40             _instance.Show();
41         }

 修改擴展記錄可以自己寫一下,比較簡單。

  下面給出一張圖關於擴展字典和擴展記錄的示意圖,便於理解之間的關系。

 


免責聲明!

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



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