cad.net 关于动态块的处理
动态块名
测试版本: Acad2008
BlockReference.IsDynamicBlock 是用来判断是否是动态块的.
当频繁使用的时候,会出现报错: eInvalidObjectId错误. System.AccessViolationException的异常
但是你要获取动态块名称的时候,直接读就好了,不需要判断它是不是动态块的.
可能的原因之一是: 块参照的Z比例为0或许不等比缩放就会令动态块变成普通块,那么导致判断动态块失效.
namespace JoinBox
{
public static partial class BlockHelper
{
/// <summary>
/// 动态块真实块名获取
/// </summary>
/// <param name="brRec">块参照</param>
/// <returns>成功返回:块的真实名称,失败返回:null</returns>
// 1.块的Z比例是0就会令动态块变成普通块,那么导致判断动态块失效
// 2.brRec.IsDynamicBlock 如果是动态块这句会报错:eInvalidObjectId
// 重复空格执行上次报这个错误,应该在所有GetObject位置写.Dispose();
public static string GetBlockName(this BlockReference brRec)
{
string blockName = string.Empty;
if (brRec.DynamicBlockTableRecord.IsOk())
{
// 动态块表记录可以获取 动态块名 也可以获取 普通块名
var btRec = brRec.DynamicBlockTableRecord.GetObject(OpenMode.ForRead) as BlockTableRecord;
blockName = btRec.Name;
btRec.Dispose();
}
return blockName;
}
}
public static partial class EntityEdit
{
/// <summary>
/// id有效,未被删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public static bool IsOk(this ObjectId id)
{
return !id.IsNull && id.IsValid && !id.IsErased && !id.IsEffectivelyErased && id.IsResident;
}
}
}
动态块过滤器
如果要构造选择集,那么把过滤器写成以下形式就好了.这可以令普通块和动态块都受惠~
#if !HC2020
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
#else
using GrxCAD.DatabaseServices;
using GrxCAD.EditorInput;
#endif
using System.Collections.Generic;
namespace JoinBox
{
public static class SsgetFilterEx
{
///https://blog.csdn.net/yxp_xa/article/details/72229202?tdsourcetag=s_pcqq_aiomsg
/// <summary>
/// 转义通配符,加入过滤器必须转义
/// </summary>
/// <param name="blockName">块名</param>
/// <returns></returns>
static string BlockNameEscape(string blockName)
{
return blockName.Replace("#", "`#").Replace("@", "`@");
}
//https://www.cnblogs.com/edata/p/6797362.html
/// <summary>
/// 通过块信息,设置动态块过滤器或普通块过滤器
/// </summary>
/// <param name="baseId">块的图元id</param>
/// <returns>过滤器</returns>
public static SelectionFilter GetBlockSelectionFilter(this Transaction tr, ObjectId baseId)
{
//选择集过滤器
var list = new List<TypedValue>();
var brRec = tr.GetObject(baseId, OpenMode.ForRead) as BlockReference;
string blockName = BlockNameEscape(brRec.GetBlockName());
list.Add(new TypedValue((int)DxfCode.Start, "INSERT")); //是块
//当前布局名称(视口内为模型)
string layoutName = CadSystem.GetMouseSpace();
list.Add(new TypedValue((int)DxfCode.LayoutName, layoutName));//是同一个空间 "*Model_Space"
//动态块过滤器{动态块名,真实名称(匿名块不提供)}
list.Add(new TypedValue((int)DxfCode.BlockName, $"`*U*,{blockName}"));
return new SelectionFilter(list.ToArray());
}
}
public static partial class CadSystem
{
/// <summary>
/// 当前布局名称(视口内为模型)
/// </summary>
/// <returns>模型或布局名称</returns>
public static string GetMouseSpace()
{
//获得当前布局名称
string layoutName = LayoutManager.Current.CurrentLayout;//切换当前布局要锁文档
if (SpatialPoint() == CadSystem.SpatialPosition.Viewport)
layoutName = "Model";
return layoutName;
}
}
}
如果你仍然会报 eInvalidObjectId 错误,我在频繁重复空格执行上次命令时候报这个错误,这个时候应该在所有GetObject开启的东西最后 .Dispose();
动态块参数
/// <summary>
/// 更改动态块拉伸参数
/// </summary>
/// <param name="ent">动态块参照的图元</param>
/// <param name="name">动作参数名</param>
/// <param name="value">动作参数值</param>
private static void ChangDynamicBlockValue(Entity ent,string name,string valueStr)
{
if (ent is BlockReference br && br.IsDynamicBlock)//如果是动态块
{
br.UpgradeOpen();
var props = br.DynamicBlockReferencePropertyCollection; //动态块属性集
foreach (DynamicBlockReferenceProperty item in props)
{
if (item.PropertyName.Contains(name))//参数名:可见性/距离之类的
item.Value = valueStr;//参数值
}
br.DowngradeOpen();
}
}
动态块未能解决的问题
怎么用纯代码的方式新建一个动态块.
edata思路:
1:弄一个空的dxf
2:构造一个有动态块的块定义
3:删除后的
弄三个自己比较.
可见性名称
例如:我需要找到"可见性"被改名之后的参数名才能设置参数值,不然缺失参数名则无法操作(因为不能枚举字符串),
发现是301组码下面:
代码参考:cad.net 句柄遍历数据库
(完)