在學習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 }
修改擴展記錄可以自己寫一下,比較簡單。
下面給出一張圖關於擴展字典和擴展記錄的示意圖,便於理解之間的關系。