在学习CAD扩展记录的过程中,遇到了一些问题,也积累了一些经验,现在给大家分享一些我的学习心得。在学习扩展字典之前需要读者了解cad的组码,也就是DxfCode。感兴趣的也可以了解一下扩展数据的相关内容(后面有时间也会分享一下,因为扩展数据、扩展字典和DxfCode组码之间有密切的关系)。
一个CAD对象只能拥有一个扩展字典,而扩展字典下面可以包含多个扩展记录。打个比方,可以这么理解,如果扩展字典相当于excel文件,那么一个扩展记录就相当于excel中的一个表单sheet对象,扩展记录中存储的数据就相当于表单sheet中的数据。
使用扩展记录可以向对象中保存一些属性数据,以便后续提取之用,这是很有用的。比如说可以向一个多段线(代表一根管线,或是其他)中存储一些施工方面的数据信息,例如施工标段、桩号范围、施工完成时间等,以后再打开图的时候,就知道这段管线是哪个施工单位施工的,什么时间完成的等等,便于查看和统计。CAD程序自身的属性对话框是无法记录这些信息的。
向对象添加扩展记录一般分为三个步骤:
1 将添加的数据构成一个类
2 编写扩展方法,包括扩展记录的添加、读取、删除、修改
3 调用扩展方法进行操作
界面如下:
下面列出主要的代码
1 将需要添加的数据构成一个类,主要包括施工标段、信息、桩号、完成时间等属性
public class XDataClass
{
public string BiaoDuan { get; set; }//施工标段
public string Information { get; set; }//附加到对象上的信息
public double StationStart { get; set; }//起始桩号
public double StationEnd { get; set; }//终止桩号
public double Length { get; private set; }//长度
public DateTime OverTime { get; set; }//完成时间
public string XRecordName { get; set; } //扩展记录名称
public XDataClass() { }
public XDataClass(string xrecordName)
{
XRecordName = xrecordName;
}
/// <summary>
/// 将扩展数据实体类转化成typevaluelist类型
/// </summary>
/// <param name="xdataClass"></param>
/// <returns></returns>
public static TypedValueList ClassToTypeValueList(XDataClass xdataClass)
{
TypedValueList tvList = new TypedValueList
{
{DxfCode.Text, xdataClass.BiaoDuan },
{DxfCode.Text, xdataClass.Information },
{DxfCode .Real ,xdataClass.StationStart },
{DxfCode.Real ,xdataClass .StationEnd },
{DxfCode.Text ,xdataClass .OverTime .ToString ("d") },
{DxfCode.Text ,xdataClass.XRecordName },
};
return tvList;
}
/// <summary>
/// 将typevaluelist类型的数据转换成实体类
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
public static XDataClass TypeValueListToClass(TypedValueList list)
{
XDataClass xdataClass = new XDataClass()
{
BiaoDuan = list[].Value.ToString(),
Information = list[].Value.ToString(),
StationStart = Convert.ToDouble(list[].Value),
StationEnd = Convert.ToDouble(list[].Value),
OverTime = Convert.ToDateTime(list[].Value),
XRecordName = list[].Value.ToString(),
Length = Math.Abs(Convert.ToDouble(list[].Value) - Convert.ToDouble(list[].Value))
};
return xdataClass;
}
}
2 编写扩展方法,包括扩展记录的添加、读取、删除、修改
#region 对象的扩展记录的添加、删除、修改
/// <summary>
/// 添加扩展记录,如果没有扩展字典,那就创建扩展字典
/// </summary>
/// <param name="objId">对象的objectid</param>
/// <param name="xRecordSearchKey">扩展记录名称</param>
/// <param name="values">扩展记录的内容</param>
/// <returns></returns>
public static bool AddXRecordToObj(this ObjectId objId, string xRecordSearchKey, TypedValueList values)
{
//添加扩展记录之前,先创建对象的扩展字典
DBObject obj = objId.GetObject(OpenMode.ForRead);//以读的方式打开
if (obj.ExtensionDictionary.IsNull)//如果对象无扩展字典,那就给创建
{
obj.UpgradeOpen();//切换对象为写的状态
obj.CreateExtensionDictionary();//为对象创建扩展字典,一个对象只能拥有一个扩展字典
obj.DowngradeOpen();//将对象切换为读的状态
}
//打开对象的扩展字典
DBDictionary dict = obj.ExtensionDictionary.GetObject(OpenMode.ForRead) as DBDictionary;
//如果扩展字典中已包含指定的扩展记录对象
if (dict.Contains(xRecordSearchKey))
{
return false;//如果包含有指定的扩展记录,那就退出
}
else //若没有包含扩展记录,则创建一个
{
Xrecord xrec = new Xrecord();//为对象创建一个扩展记录
xrec.Data = values;//指定扩展记录的内容,这里用到了自定义类型转换,TypedValueList-->ResultBuffer
dict.UpgradeOpen();//将扩展字典切换为写的状态,以便添加一个扩展记录
ObjectId xrecId = dict.SetAt(xRecordSearchKey, xrec);//在扩展字典中加入新建的扩展记录,并指定它的搜索关键字
objId.Database.TransactionManager.AddNewlyCreatedDBObject(xrec, true);
dict.DowngradeOpen();//将扩展字典切换为读的状态
return true;
}
} /// <summary>
/// 用于替换扩展字典中的整个一条扩展记录
/// </summary>
/// <param name="objId">对象id</param>
/// <param name="xRecordSearchKey">扩展记录的名称</param>
/// <param name="values">扩展记录的内容</param>
public static bool ModObjXrecord(this ObjectId objId, string xRecordSearchKey, TypedValueList values)
{
DBObject obj = objId.GetObject(OpenMode.ForRead);//以读的方式打开对象
ObjectId dictId = obj.ExtensionDictionary;//获取对象的扩展字典id
if (dictId.IsNull)
{
return false;//若对象没有扩展字典,则返回
}
//如果对象有扩展字典,则以读的方式打开
DBDictionary dict = dictId.GetObject(OpenMode.ForRead) as DBDictionary;
if (!dict.Contains(xRecordSearchKey))
{
return false;//如果扩展字典中没有包含指定关键字的扩展记录,则返回 ;
}
ObjectId xrecordId = dict.GetAt(xRecordSearchKey);//获取扩展记录的id
Xrecord xrecord = xrecordId.GetObject(OpenMode.ForWrite) as Xrecord;
xrecord.Data = values;//覆盖原来的数据,因为values有了新的指向
xrecord.DowngradeOpen();//将扩展记录切换为读的状态
return true;
} /// <summary>
/// 获取对象的扩展字典中的扩展记录
/// </summary>
/// <param name="objId">对象的id</param>
/// <param name="xRecordSearchKey">扩展记录名称</param>
/// <returns></returns>
public static TypedValueList GetObjXrecord(this ObjectId objId, string xRecordSearchKey)
{
DBObject obj = objId.GetObject(OpenMode.ForRead);//以读的方式打开对象
ObjectId dictId = obj.ExtensionDictionary;//获取对象的扩展字典的id
if (dictId.IsNull)
{
//MessageBox.Show("没有扩展字典");
return null;//若对象没有扩展字典,则返回null
}
DBDictionary dict = dictId.GetObject(OpenMode.ForRead) as DBDictionary;//获取对象的扩展字典
if (!dict.Contains(xRecordSearchKey))
{
return null;//如果扩展字典中没有包含指定关键字的扩展记录,则返回null;
}
//先要获取对象的扩展字典或图形中的有名对象字典,然后才能在字典中获取要查询的扩展记录
ObjectId xrecordId = dict.GetAt(xRecordSearchKey);//获取扩展记录对象的id
Xrecord xrecord = xrecordId.GetObject(OpenMode.ForRead) as Xrecord;//根据id获取扩展记录对象
TypedValueList values = xrecord.Data;
return values;//values 数组应该是有先后顺序的
} /// <summary>
///用于删除对象扩展字典中的指定的扩展记录
/// </summary>
/// <param name="objId">对象id</param>
/// <param name="xRecordSearchKey"> 扩展记录名称</param>
public static bool DelObjXrecord(this ObjectId objId, string xRecordSearchKey)
{
DBObject obj = objId.GetObject(OpenMode.ForRead);//以读的方式打开对象
ObjectId dictId = obj.ExtensionDictionary;//获取对象的扩展字典id
if (dictId.IsNull)
{
return false;//若对象没有扩展字典,则返回
}
//如果对象有扩展字典,则以读的方式打开
DBDictionary dict = dictId.GetObject(OpenMode.ForRead) as DBDictionary;
if (dict.Contains(xRecordSearchKey))//如果扩展字典中包含指定关键字的扩展记录,则删除;
{
dict.UpgradeOpen();//切换为写的状态
dict.Remove(xRecordSearchKey);//删除扩展记录
dict.DowngradeOpen();//切换为读的状态
}
return true;
} /// <summary>
/// 删除对象的扩展字典下的所有的扩展记录
/// 2018年4月7日09:44:12
/// </summary>
/// <param name="objId"></param>
public static bool DelObjAllXrecords(this ObjectId objId)
{
DBObject obj = objId.GetObject(OpenMode.ForRead);//以读的方式打开对象
ObjectId dictId = obj.ExtensionDictionary;//获取对象的扩展字典id
if (dictId.IsNull)
{
return false;//若对象没有扩展字典,则返回
}
//如果对象有扩展字典,则以读的方式打开
DBDictionary dict = dictId.GetObject(OpenMode.ForWrite) as DBDictionary;
//获取扩展字典下的所有扩展记录名称集合 Keys
List<string> listKeys = new List<string>();
foreach (var item in dict)//获取扩展字典中的所有条目,也就是所有的扩展记录的key
{
listKeys.Add(item.Key);
}
foreach (var key in listKeys)//根据key,删除扩展字典中的每一个条目(也就是扩展记录)
{
dict.Remove(key);
}
dict.DowngradeOpen();//切换为读的状态
return true;
} /// <summary>
/// 删除对象的扩展字典,因为每个对象只能拥有一个扩展字典,所以给定对象的objectID就好了
/// 2018年4月7日09:17:44
/// </summary>
/// <param name="objId"></param>
public static bool DeleteObjExtensionDictionary(this ObjectId objId)
{
DBObject obj = objId.GetObject(OpenMode.ForRead);//以读的方式打开对象
ObjectId dictId = obj.ExtensionDictionary;//获取对象的扩展字典的ID
if (dictId.IsNull)
{
return false; //没有扩展字典
}
//有扩展字典 obj.UpgradeOpen();//切换对象为写的状态
162 objId.DelObjAllXrecords(); //调用上面的方法,在删除扩展字典之前要先删除扩展记录
obj.ReleaseExtensionDictionary();//移除对象的扩展字典,一个对象只能拥有一个扩展字典
obj.DowngradeOpen();//将对象切换为读的状态
return true;
}
#endregion
3调用扩展方法
a 添加扩展记录
//btn 添加扩展记录
XDataClass PipeXdataClass = new XDataClass(Enum_XRcordName.pipe_whlkx.ToString());
ObjectId selectedObjId = ObjectId.Null;
private void btnAddXData_Click(object sender, EventArgs e)
{
if (CheckValue() == false)
{
return;
}
_instance.Hide();
Document doc = AcadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptEntityResult entityResult = ed.GetEntity("\n请选择一个多段线对象");//单个拾取对象
if (entityResult.Status != PromptStatus.OK)
{
_instance.Show();
return;
}
GetDataFromControls(PipeXdataClass);//私有函数,将控件中的数据填充到实体类中
//获取对象的ID
ObjectId objId = entityResult.ObjectId;
bool result = false;
using (DocumentLock docLock = doc.LockDocument())
using (Transaction trans = db.TransactionManager.StartTransaction())
{
//将xdataCalss类型的数据转换成一个typevalue型的列表
TypedValueList values = XDataClass.ClassToTypeValueList(PipeXdataClass);
result = objId.AddXRecordToObj(PipeXdataClass.XRecordName, values);
trans.Commit();
}
if (result)
{
ed.WriteMessage("\n对象的扩展数据添加成功!");
}
else
{
ed.WriteMessage("\n对象已经有扩展数据");
}
_instance.Show();
}
b 读取扩展记录
//btn 读取扩展记录
private void btnReadXData_Click(object sender, EventArgs e)
{
_instance.Hide();
ClearContent();//清空控件中的内容
Document doc = AcadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
//开始事务处理
using (DocumentLock docLock = doc.LockDocument())
using (Transaction trans = db.TransactionManager.StartTransaction())
{
PromptEntityResult entityResult = ed.GetEntity("\n请选择一个对象");//拾取单个对象
if (entityResult.Status != PromptStatus.OK)
{
ed.WriteMessage("\n取消了选择");
_instance.Show();
return;
}
//获取对象的ID
ObjectId objId = entityResult.ObjectId;
TypedValueList list = objId.GetObjXrecord(PipeXdataClass.XRecordName);
if (list is null)
{
ed.WriteMessage("\n该对象没有扩展记录");
_instance.Show();
return;
}
if (list.Count <= )
{
ed.WriteMessage("\n有扩展记录,但是记录为空");
_instance.Show();
return;
}
else
{
PipeXdataClass = XDataClass.TypeValueListToClass(list);
SetDataToControls(PipeXdataClass);//向控件中填充数据
ed.WriteMessage("\n对象扩展数据读取成功");
selectedObjId = objId;
}
}
_instance.Show();
}
c 删除扩展记录
//btn 删除
private void btnDeleteXData_Click(object sender, EventArgs e)
{
_instance.Hide();
Document doc = AcadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
//开始事务处理
using (DocumentLock docLock = doc.LockDocument())
using (Transaction trans = db.TransactionManager.StartTransaction())
{
PromptSelectionResult ss1 = ed.GetSelection();//框选对象
if (ss1.Status != PromptStatus.OK)
{
ed.WriteMessage("\n取消了选择");
_instance.Show();
return;
}
//获取对象的ID
List<ObjectId> listObjIds = ss1.Value.GetObjectIds().ToList();
int count = ;
listObjIds.ForEach(objId =>
{
if (objId.DeleteObjExtensionDictionary())
{
ed.WriteMessage("\n删除成功");
count++;
}
});
//ObjectId objId = entityResult.ObjectId;
//2018年4月7日09:50:35,经验证,必须先删除扩展字典下的所有的扩展记录,才能删除对象的扩展字典
//否则会出现错误:eContainerNotEmpty ,容器不为空
//objId.DelObjAllXrecords();
//objId.DeleteObjExtensionDictionary();
trans.Commit();
ed.WriteMessage("\n操作完成,总共删除{0}个扩展记录", count);
}
_instance.Show();
}
修改扩展记录可以自己写一下,比较简单。
下面给出一张图关于扩展字典和扩展记录的示意图,便于理解之间的关系。