05-扩展数据与字典操作教程

第五章:扩展数据与字典操作教程

5.1 扩展数据基础

5.1.1 什么是扩展数据

在AutoCAD二次开发中,我们经常需要在图元上存储自定义数据。AutoCAD提供了两种主要的数据存储方式:

  1. 扩展数据(XData):直接附加在图元上的数据
  2. 扩展字典(XDictionary):通过字典对象存储的数据

扩展数据(Extended Data,简称XData)是一种将自定义信息附加到图元的机制。每个图元最多可以存储16KB的扩展数据。

5.1.2 扩展数据的结构

扩展数据由一系列TypedValue对象组成,每个TypedValue包含一个DXF组码和对应的值:

扩展数据结构:
┌─────────────────────────────────────────┐
│ 应用程序名 (1001)                        │
├─────────────────────────────────────────┤
│ 数据项1 (1000-1071)                      │
│ 数据项2 (1000-1071)                      │
│ ...                                     │
└─────────────────────────────────────────┘

常用的扩展数据组码:

组码 数据类型 说明
1000 字符串 最多255个字符
1001 字符串 应用程序名(必须注册)
1002 字符串 控制字符串("{" 或 "}")
1003 图层名 图层名称
1010 Point3d 三维点
1040 double 实数
1041 double 距离(受比例影响)
1070 short 16位整数
1071 int 32位整数

5.1.3 注册应用程序

在使用扩展数据之前,必须先注册应用程序名称:

using var tr = new DBTrans();

// 注册应用程序
string appName = "MyApplication";
if (!tr.RegAppTable.Has(appName))
{
    tr.RegAppTable.Add(appName);
}

5.2 IFoxCAD的XDataList类

5.2.1 XDataList类设计

IFoxCAD提供了XDataList类来简化扩展数据的操作:

public class XDataList : List<TypedValue>
{
    // 应用程序名
    public string AppName { get; private set; }
    
    // 构造函数
    public XDataList(string appName);
    public XDataList(ResultBuffer resultBuffer);
    
    // 添加数据
    public void Add(DxfCode code, object value);
    public void Add(int code, object value);
    
    // 转换方法
    public ResultBuffer ToResultBuffer();
    public TypedValue[] ToArray();
}

5.2.2 创建扩展数据

using var tr = new DBTrans();

// 确保应用程序已注册
string appName = "MyApp";
if (!tr.RegAppTable.Has(appName))
{
    tr.RegAppTable.Add(appName);
}

// 创建扩展数据
var xdata = new XDataList(appName);
xdata.Add(DxfCode.ExtendedDataAsciiString, "项目编号");
xdata.Add(DxfCode.ExtendedDataAsciiString, "PRJ-001");
xdata.Add(DxfCode.ExtendedDataInteger32, 100);
xdata.Add(DxfCode.ExtendedDataReal, 3.14159);

// 选择图元并添加扩展数据
var result = tr.Editor?.GetEntity("\n请选择图元:");
if (result?.Status == PromptStatus.OK)
{
    var ent = tr.GetObject<Entity>(result.ObjectId, OpenMode.ForWrite);
    if (ent != null)
    {
        ent.XData = xdata.ToResultBuffer();
        tr.Editor?.WriteMessage("\n扩展数据已添加!");
    }
}

5.2.3 读取扩展数据

using var tr = new DBTrans();

// 选择图元
var result = tr.Editor?.GetEntity("\n请选择图元:");
if (result?.Status != PromptStatus.OK) return;

var ent = tr.GetObject<Entity>(result.ObjectId);
if (ent == null) return;

// 获取扩展数据
ResultBuffer? rb = ent.GetXDataForApplication("MyApp");
if (rb == null)
{
    tr.Editor?.WriteMessage("\n该图元没有扩展数据!");
    return;
}

// 读取数据
var xdata = new XDataList(rb);
tr.Editor?.WriteMessage("\n扩展数据内容:");
foreach (var tv in xdata)
{
    tr.Editor?.WriteMessage($"\n  组码 {tv.TypeCode}: {tv.Value}");
}

5.2.4 修改扩展数据

using var tr = new DBTrans();

var result = tr.Editor?.GetEntity("\n请选择图元:");
if (result?.Status != PromptStatus.OK) return;

var ent = tr.GetObject<Entity>(result.ObjectId, OpenMode.ForWrite);
if (ent == null) return;

// 获取现有扩展数据
string appName = "MyApp";
ResultBuffer? rb = ent.GetXDataForApplication(appName);

if (rb != null)
{
    var xdata = new XDataList(rb);
    
    // 修改数据(找到并替换)
    for (int i = 0; i < xdata.Count; i++)
    {
        if (xdata[i].TypeCode == (int)DxfCode.ExtendedDataAsciiString &&
            xdata[i].Value.ToString() == "PRJ-001")
        {
            xdata[i] = new TypedValue(
                (int)DxfCode.ExtendedDataAsciiString, "PRJ-002");
        }
    }
    
    // 保存修改
    ent.XData = xdata.ToResultBuffer();
    tr.Editor?.WriteMessage("\n扩展数据已修改!");
}

5.2.5 删除扩展数据

using var tr = new DBTrans();

var result = tr.Editor?.GetEntity("\n请选择图元:");
if (result?.Status != PromptStatus.OK) return;

var ent = tr.GetObject<Entity>(result.ObjectId, OpenMode.ForWrite);
if (ent == null) return;

// 删除特定应用程序的扩展数据
string appName = "MyApp";

// 创建只包含应用程序名的空扩展数据
var emptyXdata = new ResultBuffer(
    new TypedValue((int)DxfCode.ExtendedDataRegAppName, appName));

ent.XData = emptyXdata;
tr.Editor?.WriteMessage("\n扩展数据已删除!");

5.3 XRecordDataList类

5.3.1 什么是XRecord

XRecord(扩展记录)是另一种存储自定义数据的方式。与XData不同,XRecord没有16KB的大小限制,可以存储更多的数据。XRecord通常存储在字典中。

5.3.2 XRecordDataList类

IFoxCAD提供了XRecordDataList类来简化XRecord的操作:

public class XRecordDataList : List<TypedValue>
{
    // 添加数据
    public void Add(DxfCode code, object value);
    public void Add(int code, object value);
    
    // 转换方法
    public ResultBuffer ToResultBuffer();
    public static XRecordDataList FromResultBuffer(ResultBuffer rb);
}

5.3.3 创建和使用XRecord

using var tr = new DBTrans();

// 获取或创建自定义字典
DBDictionary myDict;
string dictName = "MyAppDict";

if (tr.NamedObjectsDict.Contains(dictName))
{
    myDict = tr.GetObject<DBDictionary>(
        tr.NamedObjectsDict.GetAt(dictName), OpenMode.ForWrite)!;
}
else
{
    using (tr.NamedObjectsDict.ForWrite())
    {
        myDict = new DBDictionary();
        tr.NamedObjectsDict.SetAt(dictName, myDict);
        tr.Transaction.AddNewlyCreatedDBObject(myDict, true);
    }
}

// 创建XRecord数据
var data = new XRecordDataList();
data.Add(DxfCode.Text, "配置项1");
data.Add(DxfCode.Text, "值1");
data.Add(DxfCode.Int32, 100);
data.Add(DxfCode.Real, 3.14159);

// 创建XRecord并存储
using (myDict.ForWrite())
{
    var xrec = new Xrecord();
    xrec.Data = data.ToResultBuffer();
    myDict.SetAt("Settings", xrec);
    tr.Transaction.AddNewlyCreatedDBObject(xrec, true);
}

tr.Editor?.WriteMessage("\n数据已保存!");

5.3.4 读取XRecord数据

using var tr = new DBTrans();

// 获取字典
string dictName = "MyAppDict";
if (!tr.NamedObjectsDict.Contains(dictName))
{
    tr.Editor?.WriteMessage("\n找不到字典!");
    return;
}

var myDict = tr.GetObject<DBDictionary>(
    tr.NamedObjectsDict.GetAt(dictName))!;

// 读取XRecord
if (!myDict.Contains("Settings"))
{
    tr.Editor?.WriteMessage("\n找不到设置!");
    return;
}

var xrec = tr.GetObject<Xrecord>(myDict.GetAt("Settings"))!;
var data = xrec.Data;

if (data != null)
{
    tr.Editor?.WriteMessage("\n读取到的数据:");
    foreach (TypedValue tv in data)
    {
        tr.Editor?.WriteMessage($"\n  组码 {tv.TypeCode}: {tv.Value}");
    }
}

5.4 图元扩展字典

5.4.1 扩展字典概念

每个DBObject(包括图元)都可以拥有自己的扩展字典(Extension Dictionary)。扩展字典可以存储任意数量的数据,不受XData 16KB的限制。

5.4.2 创建扩展字典

using var tr = new DBTrans();

// 选择图元
var result = tr.Editor?.GetEntity("\n请选择图元:");
if (result?.Status != PromptStatus.OK) return;

var ent = tr.GetObject<Entity>(result.ObjectId, OpenMode.ForWrite);
if (ent == null) return;

// 确保图元有扩展字典
ObjectId extDictId = ent.ExtensionDictionary;
DBDictionary extDict;

if (extDictId.IsNull)
{
    // 创建扩展字典
    ent.CreateExtensionDictionary();
    extDict = tr.GetObject<DBDictionary>(
        ent.ExtensionDictionary, OpenMode.ForWrite)!;
}
else
{
    extDict = tr.GetObject<DBDictionary>(extDictId, OpenMode.ForWrite)!;
}

// 在扩展字典中存储数据
var data = new XRecordDataList();
data.Add(DxfCode.Text, "设备名称");
data.Add(DxfCode.Text, "电动机M1");
data.Add(DxfCode.Real, 5.5);  // 功率
data.Add(DxfCode.Int32, 380); // 电压

using (extDict.ForWrite())
{
    var xrec = new Xrecord();
    xrec.Data = data.ToResultBuffer();
    extDict.SetAt("DeviceInfo", xrec);
    tr.Transaction.AddNewlyCreatedDBObject(xrec, true);
}

tr.Editor?.WriteMessage("\n设备信息已保存到图元扩展字典!");

5.4.3 读取扩展字典

using var tr = new DBTrans();

var result = tr.Editor?.GetEntity("\n请选择图元:");
if (result?.Status != PromptStatus.OK) return;

var ent = tr.GetObject<Entity>(result.ObjectId);
if (ent == null) return;

// 获取扩展字典
if (ent.ExtensionDictionary.IsNull)
{
    tr.Editor?.WriteMessage("\n该图元没有扩展字典!");
    return;
}

var extDict = tr.GetObject<DBDictionary>(ent.ExtensionDictionary)!;

// 读取数据
if (!extDict.Contains("DeviceInfo"))
{
    tr.Editor?.WriteMessage("\n找不到设备信息!");
    return;
}

var xrec = tr.GetObject<Xrecord>(extDict.GetAt("DeviceInfo"))!;
if (xrec.Data != null)
{
    tr.Editor?.WriteMessage("\n设备信息:");
    var tvs = xrec.Data.AsArray();
    for (int i = 0; i < tvs.Length; i += 2)
    {
        if (i + 1 < tvs.Length)
        {
            tr.Editor?.WriteMessage($"\n  {tvs[i].Value}: {tvs[i + 1].Value}");
        }
    }
}

5.5 命名对象字典操作

5.5.1 命名对象字典结构

命名对象字典(Named Objects Dictionary)是数据库的根字典,可以存储自定义的字典和数据。

命名对象字典
├── ACAD_GROUP (组字典)
├── ACAD_LAYOUT (布局字典)
├── ACAD_MATERIAL (材质字典)
├── MyAppDict (自定义字典)
│   ├── Settings
│   ├── UserData
│   └── ...
└── ...

5.5.2 创建自定义字典层次

using var tr = new DBTrans();

// 创建多层字典结构
// MyApp
// ├── Config
// │   ├── General
// │   └── Advanced
// └── Data
//     ├── Projects
//     └── Users

// 获取或创建根字典
DBDictionary GetOrCreateDict(DBDictionary parent, string name)
{
    using (parent.ForWrite())
    {
        if (parent.Contains(name))
        {
            return tr.GetObject<DBDictionary>(parent.GetAt(name))!;
        }
        else
        {
            var dict = new DBDictionary();
            parent.SetAt(name, dict);
            tr.Transaction.AddNewlyCreatedDBObject(dict, true);
            return dict;
        }
    }
}

// 创建字典结构
var rootDict = GetOrCreateDict(tr.NamedObjectsDict, "MyApp");
var configDict = GetOrCreateDict(rootDict, "Config");
var generalDict = GetOrCreateDict(configDict, "General");
var advancedDict = GetOrCreateDict(configDict, "Advanced");
var dataDict = GetOrCreateDict(rootDict, "Data");
var projectsDict = GetOrCreateDict(dataDict, "Projects");
var usersDict = GetOrCreateDict(dataDict, "Users");

tr.Editor?.WriteMessage("\n字典结构创建完成!");

5.5.3 存储复杂数据

using var tr = new DBTrans();

// 获取字典
var rootDict = tr.GetObject<DBDictionary>(
    tr.NamedObjectsDict.GetAt("MyApp"), OpenMode.ForWrite)!;
var projectsDict = tr.GetObject<DBDictionary>(
    tr.GetObject<DBDictionary>(rootDict.GetAt("Data"))!.GetAt("Projects"),
    OpenMode.ForWrite)!;

// 存储项目数据
void SaveProject(string projectId, string name, string description, 
    double area, DateTime createDate)
{
    var data = new XRecordDataList();
    data.Add(DxfCode.Text, "Name");
    data.Add(DxfCode.Text, name);
    data.Add(DxfCode.Text, "Description");
    data.Add(DxfCode.Text, description);
    data.Add(DxfCode.Text, "Area");
    data.Add(DxfCode.Real, area);
    data.Add(DxfCode.Text, "CreateDate");
    data.Add(DxfCode.Text, createDate.ToString("yyyy-MM-dd"));
    
    using (projectsDict.ForWrite())
    {
        Xrecord xrec;
        if (projectsDict.Contains(projectId))
        {
            xrec = tr.GetObject<Xrecord>(
                projectsDict.GetAt(projectId), OpenMode.ForWrite)!;
        }
        else
        {
            xrec = new Xrecord();
            projectsDict.SetAt(projectId, xrec);
            tr.Transaction.AddNewlyCreatedDBObject(xrec, true);
        }
        xrec.Data = data.ToResultBuffer();
    }
}

// 保存几个项目
SaveProject("PRJ001", "办公楼项目", "市中心办公楼设计", 5000.0, DateTime.Now);
SaveProject("PRJ002", "住宅项目", "高层住宅小区", 12000.0, DateTime.Now);
SaveProject("PRJ003", "商业中心", "购物中心设计", 8000.0, DateTime.Now);

tr.Editor?.WriteMessage("\n项目数据已保存!");

5.5.4 读取和遍历字典

using var tr = new DBTrans();

// 遍历所有项目
if (!tr.NamedObjectsDict.Contains("MyApp"))
{
    tr.Editor?.WriteMessage("\n找不到应用数据!");
    return;
}

var rootDict = tr.GetObject<DBDictionary>(
    tr.NamedObjectsDict.GetAt("MyApp"))!;

if (!rootDict.Contains("Data")) return;
var dataDict = tr.GetObject<DBDictionary>(rootDict.GetAt("Data"))!;

if (!dataDict.Contains("Projects")) return;
var projectsDict = tr.GetObject<DBDictionary>(dataDict.GetAt("Projects"))!;

tr.Editor?.WriteMessage("\n项目列表:");
tr.Editor?.WriteMessage("\n" + new string('-', 60));

foreach (DBDictionaryEntry entry in projectsDict)
{
    string projectId = entry.Key;
    var xrec = tr.GetObject<Xrecord>(entry.Value)!;
    
    if (xrec.Data != null)
    {
        var data = xrec.Data.AsArray();
        
        // 解析数据
        Dictionary<string, string> project = new();
        for (int i = 0; i < data.Length; i += 2)
        {
            if (i + 1 < data.Length)
            {
                project[data[i].Value.ToString()!] = data[i + 1].Value.ToString()!;
            }
        }
        
        tr.Editor?.WriteMessage($"\n项目ID: {projectId}");
        tr.Editor?.WriteMessage($"\n  名称: {project.GetValueOrDefault("Name", "")}");
        tr.Editor?.WriteMessage($"\n  描述: {project.GetValueOrDefault("Description", "")}");
        tr.Editor?.WriteMessage($"\n  面积: {project.GetValueOrDefault("Area", "")}");
        tr.Editor?.WriteMessage($"\n  创建日期: {project.GetValueOrDefault("CreateDate", "")}");
        tr.Editor?.WriteMessage("\n");
    }
}

5.6 实体与数据关联

5.6.1 建立图元数据关联

一种常见的需求是将图形中的图元与外部数据关联。可以使用XData存储标识符:

using var tr = new DBTrans();

// 确保应用程序已注册
string appName = "MyDataLink";
if (!tr.RegAppTable.Has(appName))
{
    tr.RegAppTable.Add(appName);
}

// 为图元添加数据标识
void LinkEntityToData(Entity ent, string dataId)
{
    using (ent.ForWrite())
    {
        var xdata = new XDataList(appName);
        xdata.Add(DxfCode.ExtendedDataAsciiString, "DataLink");
        xdata.Add(DxfCode.ExtendedDataAsciiString, dataId);
        ent.XData = xdata.ToResultBuffer();
    }
}

// 获取图元关联的数据ID
string? GetLinkedDataId(Entity ent)
{
    var rb = ent.GetXDataForApplication(appName);
    if (rb == null) return null;
    
    var data = rb.AsArray();
    for (int i = 0; i < data.Length - 1; i++)
    {
        if (data[i].Value.ToString() == "DataLink")
        {
            return data[i + 1].Value.ToString();
        }
    }
    return null;
}

// 示例:为选择的图元添加关联
var result = tr.Editor?.GetSelection();
if (result?.Status == PromptStatus.OK)
{
    int index = 1;
    foreach (SelectedObject obj in result.Value)
    {
        if (obj == null) continue;
        
        var ent = tr.GetObject<Entity>(obj.ObjectId, OpenMode.ForWrite);
        if (ent != null)
        {
            string dataId = $"DATA_{index:D5}";
            LinkEntityToData(ent, dataId);
            index++;
        }
    }
    
    tr.Editor?.WriteMessage($"\n已为 {result.Value.Count} 个图元添加数据关联!");
}

5.6.2 查找关联图元

using var tr = new DBTrans();

// 查找所有有数据关联的图元
string appName = "MyDataLink";

var filter = OpFilter.Build(e => e.Dxf(-3) == appName);
var result = tr.Editor?.SelectAll(filter);

if (result?.Status == PromptStatus.OK)
{
    tr.Editor?.WriteMessage("\n关联的图元:");
    
    foreach (SelectedObject obj in result.Value)
    {
        if (obj == null) continue;
        
        var ent = tr.GetObject<Entity>(obj.ObjectId);
        if (ent == null) continue;
        
        var rb = ent.GetXDataForApplication(appName);
        if (rb != null)
        {
            var data = rb.AsArray();
            for (int i = 0; i < data.Length - 1; i++)
            {
                if (data[i].Value.ToString() == "DataLink")
                {
                    tr.Editor?.WriteMessage(
                        $"\n  {ent.GetType().Name} -> {data[i + 1].Value}");
                    break;
                }
            }
        }
    }
}

5.7 数据持久化方案

5.7.1 文档级数据存储

对于需要在文档中持久化的应用配置,可以使用命名对象字典:

public class DocumentDataManager
{
    private const string RootDictName = "MyAppSettings";
    
    public static void SaveSetting(string key, object value)
    {
        using var tr = new DBTrans();
        
        // 获取或创建设置字典
        DBDictionary settingsDict;
        if (tr.NamedObjectsDict.Contains(RootDictName))
        {
            settingsDict = tr.GetObject<DBDictionary>(
                tr.NamedObjectsDict.GetAt(RootDictName), OpenMode.ForWrite)!;
        }
        else
        {
            using (tr.NamedObjectsDict.ForWrite())
            {
                settingsDict = new DBDictionary();
                tr.NamedObjectsDict.SetAt(RootDictName, settingsDict);
                tr.Transaction.AddNewlyCreatedDBObject(settingsDict, true);
            }
        }
        
        // 保存设置
        var data = new ResultBuffer(
            new TypedValue((int)DxfCode.Text, value.ToString()));
        
        using (settingsDict.ForWrite())
        {
            Xrecord xrec;
            if (settingsDict.Contains(key))
            {
                xrec = tr.GetObject<Xrecord>(
                    settingsDict.GetAt(key), OpenMode.ForWrite)!;
            }
            else
            {
                xrec = new Xrecord();
                settingsDict.SetAt(key, xrec);
                tr.Transaction.AddNewlyCreatedDBObject(xrec, true);
            }
            xrec.Data = data;
        }
    }
    
    public static string? GetSetting(string key)
    {
        using var tr = new DBTrans();
        
        if (!tr.NamedObjectsDict.Contains(RootDictName))
            return null;
        
        var settingsDict = tr.GetObject<DBDictionary>(
            tr.NamedObjectsDict.GetAt(RootDictName))!;
        
        if (!settingsDict.Contains(key))
            return null;
        
        var xrec = tr.GetObject<Xrecord>(settingsDict.GetAt(key))!;
        if (xrec.Data == null) return null;
        
        var tvs = xrec.Data.AsArray();
        return tvs.Length > 0 ? tvs[0].Value.ToString() : null;
    }
}

5.7.2 使用示例

[CommandMethod("SaveConfig")]
public void SaveConfiguration()
{
    using var tr = new DBTrans();
    
    // 保存各种设置
    DocumentDataManager.SaveSetting("ProjectName", "示例项目");
    DocumentDataManager.SaveSetting("Author", "张三");
    DocumentDataManager.SaveSetting("Version", "1.0.0");
    DocumentDataManager.SaveSetting("LastModified", DateTime.Now.ToString());
    
    tr.Editor?.WriteMessage("\n配置已保存!");
}

[CommandMethod("LoadConfig")]
public void LoadConfiguration()
{
    using var tr = new DBTrans();
    
    tr.Editor?.WriteMessage("\n项目配置:");
    tr.Editor?.WriteMessage($"\n  项目名称: {DocumentDataManager.GetSetting("ProjectName")}");
    tr.Editor?.WriteMessage($"\n  作者: {DocumentDataManager.GetSetting("Author")}");
    tr.Editor?.WriteMessage($"\n  版本: {DocumentDataManager.GetSetting("Version")}");
    tr.Editor?.WriteMessage($"\n  最后修改: {DocumentDataManager.GetSetting("LastModified")}");
}

5.8 最佳实践

5.8.1 选择合适的存储方式

存储方式 适用场景 优点 缺点
XData 小量图元数据 直接关联图元 16KB限制
扩展字典 大量图元数据 无大小限制 需要额外管理
命名对象字典 全局配置数据 易于访问 与图元无直接关联

5.8.2 数据版本管理

public class DataVersionManager
{
    private const string VersionKey = "_DataVersion";
    private const string CurrentVersion = "2.0";
    
    public static bool NeedsMigration()
    {
        string? version = DocumentDataManager.GetSetting(VersionKey);
        return version != CurrentVersion;
    }
    
    public static void MigrateData()
    {
        string? version = DocumentDataManager.GetSetting(VersionKey);
        
        if (string.IsNullOrEmpty(version))
        {
            // 从无版本迁移
            MigrateFromV0();
        }
        else if (version == "1.0")
        {
            // 从1.0迁移到2.0
            MigrateFromV1();
        }
        
        // 更新版本号
        DocumentDataManager.SaveSetting(VersionKey, CurrentVersion);
    }
    
    private static void MigrateFromV0()
    {
        // 迁移旧版本数据的逻辑
    }
    
    private static void MigrateFromV1()
    {
        // 从1.0迁移到2.0的逻辑
    }
}

5.8.3 错误处理

public static class SafeDataAccess
{
    public static T? GetData<T>(Func<T> accessor, T? defaultValue = default)
    {
        try
        {
            return accessor();
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"数据访问错误: {ex.Message}");
            return defaultValue;
        }
    }
    
    public static bool TrySetData(Action setter, out string? error)
    {
        try
        {
            setter();
            error = null;
            return true;
        }
        catch (Exception ex)
        {
            error = ex.Message;
            return false;
        }
    }
}

// 使用示例
var projectName = SafeDataAccess.GetData(
    () => DocumentDataManager.GetSetting("ProjectName"),
    "未命名项目");

if (!SafeDataAccess.TrySetData(
    () => DocumentDataManager.SaveSetting("Key", "Value"),
    out var error))
{
    // 处理错误
}

5.9 本章小结

本章我们深入学习了IFoxCAD的扩展数据和字典操作:

  1. 扩展数据基础:理解了XData的概念、结构和组码
  2. XDataList类:学习了创建、读取、修改和删除扩展数据
  3. XRecordDataList类:掌握了XRecord的创建和使用
  4. 图元扩展字典:学习了如何为图元创建和使用扩展字典
  5. 命名对象字典:掌握了创建字典层次和存储复杂数据
  6. 实体数据关联:学习了如何建立图元与数据的关联
  7. 数据持久化:了解了文档级数据存储的方案
  8. 最佳实践:学习了存储方式选择、版本管理和错误处理

扩展数据和字典是CAD二次开发中数据存储的核心机制,掌握这些技术对于开发功能完整的CAD插件至关重要。下一章我们将学习IFoxCAD的扩展方法体系。

posted @ 2025-11-27 12:00  我才是银古  阅读(0)  评论(0)    收藏  举报