本文章的目的是,在预先不知道一个块是否有可见性选项的前提下,拿到它的可见性属性和列表。
由于这几天突然有此需求,所以查找相应的方法,发现.net没有提供直接的api,且未找到可靠的方法。

一、错误方法

1. 通过名称判断

飞诗跟我说我通过判断PropertyName是否包含"可见性"来判断,并且跟我说这个"可见性"是不能改的,是固定的。
但是经过我的测试,块的可见性名字在块编辑界面可以通过特性栏来修改。 可见性1.png

2. 通过PropertyTypeCode和GetAllowedValues来判断

我们知道DynamicBlockReferenceProperty有一个PropertyTypeCode属性和GetAllowedValues方法,code==5时代表类型是string,有下拉列表时GetAllowedValues可以拿到一个字符串集合。
我还想过通过夹点来辅助判断,因为可见性会使动态块增加一个夹点(点击出现下拉列表那个),这个夹点的属性HotGripInvokesRightClick==true(默认为false),那么这样做是否完全可靠呢?

答案是否定的,因为在动态块里面还有一个叫作"查询"的东西 可见性2.png 这个查询的propertyCode同样==5,并且GetAllowedValues同样会拿到一个字符串列表,且同样会增加一个和可见性一模一样的夹点,无法区分出是查询还是可见性。

二、可靠方法

在我觉得反正没什么人用这个查询,就使用上述第二种方法凑合一下的时候。
水友 @执着 给我提供了一段 Lee Mac 的lisp代码,可以通过块表记录的扩展字典和组码来获取到。
经过我的一番尝试和测试,最终使用c#实现,代码如下。

/// <summary>
/// 获取块可见性信息
/// </summary>
/// <param name="btr">块表记录</param>
/// <returns>可见性信息</returns>
public static BlockVisibilityInfo GetVisibilityInfo(this BlockTableRecord btr)
{
    var info = new BlockVisibilityInfo();
    if (btr.IsDynamicBlock && btr.ExtensionDictionary.IsOk())
    {
        var dict = btr.GetXDictionary();
        if (dict.Contains("ACAD_ENHANCEDBLOCK"))
        {
            var idEnhancedBlock = dict.GetAt("ACAD_ENHANCEDBLOCK");
            var enhancedBlockTypedValues = Env.EntGet(idEnhancedBlock);
            var parm = enhancedBlockTypedValues.FirstOrDefault(e =>
                    e.TypeCode == 360 && e.Value is ObjectId id && id.IsOk() &&
                    id.ObjectClass.DxfName == "BLOCKVISIBILITYPARAMETER")
                .Value;
            if (parm is ObjectId parmId)
            {
                info.Has = true;
                var parmTypedValues = Env.EntGet(parmId);
                info.PropertyName = parmTypedValues.FirstOrDefault(e => e.TypeCode == 301)
                    .Value?.ToString() ?? "";
                info.AllowedValues = parmTypedValues.Where(e => e.TypeCode == 303)
                    .Select(e => e.Value?.ToString() ?? "")
                    .Where(e => !string.IsNullOrWhiteSpace(e))
                    .ToList();
            }
        }
    }
    return info;
}

/// <summary>
/// 块可见性信息
/// </summary>
public class BlockVisibilityInfo
{
    /// <summary>
    /// 有无可见性
    /// </summary>
    public bool Has { get; set; }
    /// <summary>
    /// 属性名
    /// </summary>
    public string PropertyName { get; set; } = "";
    /// <summary>
    /// 允许值
    /// </summary>
    public List<string> AllowedValues { get; set; } = [];
}

上述代码已提交至IFoxCad v0.9分支

具体流程为:

  • 获取动态块的原块表记录
  • 判断块表记录是否有扩展字典
  • 判断扩展字典里是否有key为"ACAD_ENHANCEDBLOCK"的项,拿到对应的ObjectId1
  • 对ObjectId1进行entget,拿到组码列表1
  • 遍历组码列表1中所有组码为360的ObjectId,判断是否有dxfName为"BLOCKVISIBILITYPARAMETER"的ObjectId2(只会有一个或没有)
  • 如果能找到ObjectId2那么说明此动态块有可见性列表
  • 对ObjectId2再次进行entget,拿到组码列表2
  • 遍历组码列表2,301组码对应的值为可见性的名字(PropertyName),303组码(可能有多个)对应的值为允许值(GetAllowedValues)

EntGet如果不知道如何使用,参考下面以前发过的文章。

https://dyhcad.cn/archives/5d55ded7-6a09-4552-af3f-1d979d310524