You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AutoCAD C#:如何在可编辑保存的对话框中展示Xdata并调用窗体

AutoCAD 扩展数据(Xdata) 窗体编辑实现方案

核心问题排查

原有代码无法正常实现功能的原因:

  • 在Form1_Load方法内局部声明的ListView属于方法级变量,创建后未加入窗体的Controls控件集合,运行时不会在窗体上渲染
  • 原生ListView默认关闭行编辑能力,未配置对应属性时无法支持用户修改内容
  • 跨类调用窗体时如果使用全局静态实例、非模态调用,在AutoCAD运行环境下极易出现界面锁死、权限报错问题

可直接落地的实现代码

首先完成窗体端的控件初始化、Xdata加载、保存回写逻辑:

public partial class Form1 : Form
{
    // ListView声明为窗体级字段,不要放在Load方法内作为局部变量
    private ListView listViewXdata;
    // 存储当前操作的实体ObjectId,避免跨类传值混乱
    private ObjectId _targetEntId;

    // 重载构造函数,直接传入需要编辑的实体ID
    public Form1(ObjectId targetEntId)
    {
        InitializeComponent();
        _targetEntId = targetEntId;
        InitControlConfig();
    }

    // 初始化控件配置
    private void InitControlConfig()
    {
        listViewXdata = new ListView
        {
            Dock = DockStyle.Top,
            Height = 350,
            View = View.Details,
            FullRowSelect = true,
            LabelEdit = true,
            GridLines = true
        };
        // 配置两列展示:Xdata组码类型、对应值
        listViewXdata.Columns.Add("扩展数据项", 150);
        listViewXdata.Columns.Add("值", 250);

        Button btnSave = new Button
        {
            Text = "保存修改",
            Dock = DockStyle.Bottom,
            Height = 30
        };
        btnSave.Click += BtnSave_Click;

        // *关键:必须把控件加入窗体控件集合,否则运行时不会显示*
        this.Controls.Add(listViewXdata);
        this.Controls.Add(btnSave);
        this.Width = 450;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        // Load事件只做数据加载,不要在这里初始化控件
        Database db = HostApplicationServices.WorkingDatabase;
        using (Transaction tr = db.TransactionManager.StartTransaction())
        {
            Entity ent = tr.GetObject(_targetEntId, OpenMode.ForRead) as Entity;
            if (ent == null) return;
            ResultBuffer xdata = ent.XData;
            if (xdata == null)
            {
                MessageBox.Show("所选实体无扩展数据");
                return;
            }
            // 遍历Xdata填充到ListView
            foreach (TypedValue tv in xdata)
            {
                ListViewItem item = new ListViewItem(tv.TypeCode.ToString());
                item.SubItems.Add(tv.Value?.ToString() ?? "");
                // 原始TypedValue存在Tag属性中,保存时直接读取做类型转换
                item.Tag = tv;
                listViewXdata.Items.Add(item);
            }
            tr.Commit();
        }
    }

    // 保存修改回写Xdata
    private void BtnSave_Click(object sender, EventArgs e)
    {
        Database db = HostApplicationServices.WorkingDatabase;
        // 写操作前必须锁文档,否则会抛权限异常
        using (DocumentLock docLock = Application.DocumentManager.MdiActiveDocument.LockDocument())
        using (Transaction tr = db.TransactionManager.StartTransaction())
        {
            Entity ent = tr.GetObject(_targetEntId, OpenMode.ForWrite) as Entity;
            if (ent == null) return;
            List<TypedValue> newXdata = new List<TypedValue>();
            foreach (ListViewItem item in listViewXdata.Items)
            {
                TypedValue oldTv = (TypedValue)item.Tag;
                // 可根据实际组码类型做对应类型转换,示例默认按字符串存储
                newXdata.Add(new TypedValue(oldTv.TypeCode, item.SubItems[1].Text));
            }
            ent.XData = new ResultBuffer(newXdata.ToArray());
            tr.Commit();
        }
        MessageBox.Show("扩展数据保存成功");
        this.Close();
    }
}

注:原生ListView默认仅支持编辑第一列内容,如果需要直接编辑第二列的值,需要额外写双击事件挂载输入框,嫌实现麻烦可以直接替换为DataGridView控件,原生支持多列编辑,整体逻辑和上述代码一致

其他类调用Form1的正确方式

不要声明全局静态的窗体实例,在需要弹出窗体的逻辑中直接新建实例传入参数即可,AutoCAD环境下必须用模态方式弹出,避免和CAD主窗口抢焦点导致锁死:

// 你的自定义命令类中的触发方法
[CommandMethod("EditXdata")]
public void EditXdataCommand()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        // 让用户选择需要编辑Xdata的实体
        PromptEntityOptions peo = new PromptEntityOptions("请选择要编辑扩展数据的实体");
        PromptEntityResult per = doc.Editor.GetEntity(peo);
        if (per.Status != PromptStatus.OK) return;
        // 新建窗体实例,传入选中实体的ID
        Form1 xdataForm = new Form1(per.ObjectId);
        // 用AutoCAD官方API模态弹出窗体,不要直接调用Show()方法
        Application.ShowModalDialog(xdataForm);
        tr.Commit();
    }
}

注意事项

  • 所有涉及AutoCAD实体写操作的逻辑,必须先锁文档、以写模式打开实体,否则会抛出eNotOpenForWrite类异常
  • 不要在自行开启的子线程中操作窗体控件或AutoCAD数据库对象,避免跨线程报错
  • 如果Xdata包含复杂类型数据(比如句柄、坐标、二进制数据),保存时需要根据组码对应的数据类型做转换,不要统一按字符串存储

内容的提问来源于stack exchange,提问作者jasontho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 01:39:35