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 }
修改扩展记录可以自己写一下,比较简单。
下面给出一张图关于扩展字典和扩展记录的示意图,便于理解之间的关系。