数据管理
TIP
本部分依赖数据模块,即需要安装AnyCAD.Platform.NET模块。
数据管理模块提供基于文档的数据管理方式,支持文件的读写、对象增删改查、事务机制(Undo/Redo)等功能。
虽然基于基础模块也能开发应用,但对于比较复杂的应用,比如需要文件保存/事务回退等功能,基于数据管理模块提供的基础能力,可以大大提升应用的开发效率。
1. 核心概念
应用 Application
全局唯一
用来管理多文档、多视图。可以用来获取全局对象,如当前活动的视图、文档等。
文档 Document
即对象的容器。
只有在Document中的对象才能够被序列化、支持事务处理。
// 获取当前活动的文档
var doc = Application.Instance().GetActiveDocument();
基本对象 Element
图元或对象的基类,可以是实体构件,也可以是材质、分组等虚拟对象。
保存在文档里的对象均为Element。每个Element对象都会分配全局唯一的Id。通过Id可以从文档中查找对象。
从Element的API文档中的类图可以看到,从Element继承了若干的子类,以满足不同的应用需求。
视图 DbViewBase
我们对文档多个维度查看,每个维度称之为视图。
AnyCAD支持多视图。创建文档的时候,默认创建三维视图。在单视图应用可以忽略视图的存在。
事务 UndoTransaction
即Undo/Redo功能
对Document、Element的增删改均需要使用事务对象来管理。其一般的范式为:
var undo = new UndoTransaction(doc);
undo.Start("Modify"); // 自己定义本次事务的内容
{
// 这里对文档、图元操作处理
}
undo.Commit(); //提交事务
2. 增删改查
与数据库一样,AnyCAD支持对文档内的对象记录的增删改查。
以创建几何实体图元 ShapeElement 为例, 实现对象增删改查。
TIP
ShapeElement用来保存几何对象,对于大多数用户创建的几何实体保存在此对象即可。
增加和修改
// 创建文档
var doc = Application.Instance().CreateDocument("我的文档");
// 显示文档
Application.Instance().ShowDocument(doc);
ObjectId shapeId;
// 添加对象
var undo = new UndoTransaction(doc);
undo.Start("Add"); // 自己定义本次事务的内容
{
// ShapeElement
var se = ShapeElement.Create(doc);
// 创建几何对象
var shape = ShapeBuilder.MakeBox(....);
se.SetShape(se);
shapeId = se.GetId();
}
undo.Commit(); //提交事务
删除
通过对象ID从文档中删除对象。
// 删除对象
var undo = new UndoTransaction(doc);
undo.Start("Remove"); // 自己定义本次事务的内容
{
doc.RemoveElement(shapeId);
}
undo.Commit(); //提交事务
查找
- 根据ID查找对象
var se = ShapeElement.Cast(doc.FindElement(shapeId));
- 遍历文档
使用ElementIterator遍历文档全部的对象:
for(var itr = ElementIterator.Create(doc); itr.More(); itr.Next())
{
var e = itr.Current();
//...
}
- 遍历某类对象
遍历ShapeElement类型的对象
var itr = ElementIterator.Create(doc, ShapeElement.GetStaticClassId());
for(; itr.More(); itr.Next())
{
var e = ShapeElement.Cast(itr.Current());
if(e == null)
continue;
//...
}
3. 文档监听
使用DocumentListener继承的子类可以监听文档变化状态,以便及时更新界面状态。
把对象注册到事件管理器DocumentEvent
- 定义监听器
class MyDocumentListener : DocumentListener
{
public MyDocumentListener()
{
SetName("HelloWorld");
}
public override AfterDocumentChanged (Document doc, DocumentEventArgs args)
{
// 根据args状态判断是否需要更新界面,比如构件目录树
}
public override OnSelectionChanged(Document doc, ObjectId viewId)
{
// 选择集发生变化,用来更新构件树上选择状态、属性表上的属性等
}
}
- 注册监听器
//一般声明为成员变量
MyDocumentListener _DocListener = new MyDocumentListener();
DocumentEvent.Instance().AddListener(_DocListener);
// ...
- 移除监听器
// 必要的地方移除
DocumentEvent.Instance().RemoveListener (_DocListener);
4. 对象显示
基于数据模块,开发者不需要直接操作显示场景,对Element的增删改会自动更新于文档绑定的视图。
5. 对象选择
使用Document对象的Select选择对象,使用GetSelection方法获取选中对象ID集合。
- 视图选择
用户点击视图选择对象会自动更新Document的选择集
- 手动选择
如通过选择目录树的一项选择
ObjectIdList ids = new ObjectIdList();
ids.Add(id);
doc.Select(ids);
// 视图里对应的对象会高亮显示。
// 会自动触发SelectionChanged消息,通过DocumentListener可获取到。
- 选择集查询
var ids = doc.GetSelection();
foreach(var id in ids)
{
//...
}
6. 文档存储
DocumentIO提供Save/Load方法可以保存和加载文档。
- 保存
DocumentIO.Save(doc, "d:/ssss.acad");
- 读取
var doc = DocumentIO.Load("d:/ssss.acad");
if(doc != null)
{
//显示文档
Application.Instance().ShowDocument(doc);
}
7. 小结
使用数据管理模块,需要按照数据模块管理的规则使用,尤其注意事务机制的使用方法。通过DocumentListener可以实现界面与视图之间的解耦,在需要获取文档变化、选择状态的地方均可以注册相应的DocumentListener来对文档监听。
为方便数据模块的在WPF中的使用,可以结合AnyCAD.AppFramework.NET MVVM框架,可大大简化代码量。请参考示例程序源码 anycad.rapid.cax。