如图所示:我才用代码读取 某一个参数cell 的 属性(参数),发现可以读取 Genneral、Geometry、Raw Data、等板块的信息,但是 Variables 板块的信息 没有读取到, 请问大神 是什么原因?
具体代码如下:
bool doubleClickCallbackFunc2(DisplayPathCP path) { WString filename; ElementRefP eP = path->GetHeadElem(); DgnModelRefP currFileP = mdlDisplayPath_getPathRoot(path); MSElementDescrP elDescr; mdlElmdscr_getByElemRef(&elDescr, eP, currFileP, FALSE, NULL); EditElementHandle eeh(elDescr, FALSE, TRUE , 0); FindInstancesScopePtr scope = FindInstancesScope::CreateScope(eeh, FindInstancesScopeOption(DgnECHostType::All)); ECQueryPtr query = ECQuery::CreateQuery(ECQUERY_PROCESS_SearchAllClasses); DgnECInstanceIterable iterable = Bentley::DgnPlatform::DgnECManager::GetManager().FindInstances(*scope, *query); DgnECInstancePtr instance = *((iterable.begin())); ECN::ECClassCR instanceClass = instance->GetClass(); ECPropertyIterable properties = instanceClass.GetProperties(); for (ECPropertyIterable::const_iterator it0 = properties.begin(); it0 != properties.end(); ++it0) { ECValue v; ECPropertyCP pProp = (*it0); WString ddeea = pProp->GetTypeName(); WString ecpName = pProp->GetName(); WString ecpDesc = pProp->GetDescription(); WString ecpVVV = pProp->GetInvariantDescription(); WString ersV = pProp->GetDisplayLabel(); mdlDialog_dmsgsPrint(WPrintfString(L"名称:%s 类型:%s 内容:%s", ecpName, ddeea, ersV)); } filename.Sprintf(L"D:\\1.xml"); instance->WriteToXmlFile(filename.data(), true, true); instance->WriteChanges(); mdlDialog_dmsgsPrint(WPrintfString(L"名称:%s 内容:%s ", L"长度:", L"123" )); return true; }
这个帖子里边的方法您试过没有:https://communities.bentley.com/communities/other_communities/chinafirst/f/microstation-projectwise/143095/c-ce
测试过了,我编写的demo 就是根据 上面的代码 进行的修改,但是 还死活不能获取 图中 标红部分的 参数信息,也就是 我们设置的尺寸信息 或 与约束相关的信息,也就是 edit item 部分的变量 ,遍历不出来。
Bentley 二次开发小白一枚
老师好!
针对您的回复,还是不太明白,见谅!!
另外,上面您的方法 可以读取到 哪些属性信息吗?或者 怎么样才能可以读出来那些信息呢?
请老师 指点!!!!!
老师 我这里 还有一部分代码,可以完全替代上面我编写 的那段代码,可以检索到 我想要 检索的 变量名称 类型等 信息。
但是 我 看不出来 他们的区别 ,您看一下 ,帮我解读一下 ,从业务逻辑 和 结构上 ,谢谢老师 !!!!
ElementRefP eP = path->GetHeadElem(); DgnModelRefP currFileP = mdlDisplayPath_getPathRoot(path); int itype=elementRef_getElemType(eP); MSElementDescrP elDescr; mdlElmdscr_getByElemRef(&elDescr, eP, currFileP, FALSE, NULL); ParametricCellDefHandler& defHdler = ParametricCellDefHandler::GetInstance(); BeFileName activeCellLibraryName; DgnFileP pLibObj; WChar wCellName[MAX_CELLNAME_LENGTH]; DgnFileP pDgnFile = ISessionMgr::GetActiveDgnFile(); int iStatus; DgnIndexIteratorP pDgnIndexIterator; DgnIndexItemP pDgnIndexItem; ElementRefP ElDefRef=NULL; DgnPlatform::DgnModelType ctype; bool is3D; mdlCell_getLibraryName(activeCellLibraryName);//此处是读取激活的存放cell目录或.cel文件 iStatus = mdlCell_getLibraryObject(&pLibObj, activeCellLibraryName.c_str(), true); pDgnIndexIterator = mdlModelIterator_create(pLibObj); mdlModelIterator_setAcceptCellsOnly(pDgnIndexIterator, true); /*下面是一个遍历模板库(cell文件)中模型的功能,要求改模板库只能有一个模型,也就是说找到一个模型后即可停止遍历 ,并获取改模型的名称和其他信息。然后从该模型中获取cell的参数化信息。这里有一个非常重要的前提,就是需要明确 一个模板库必须且只能有一个模型,每个模型中只能有一个cell的强烈要求和限制。通过这个规则来进行约束。 因此目前这个遍历模板库中模型的算法,也就丧失了意义,因为根本不存在遍历的条件或基础。 */ while (pDgnIndexItem = mdlModelIterator_getNext(pDgnIndexIterator) ) { mdlModelItem_getName(pDgnIndexItem, wCellName, MAX_CELLNAME_LENGTH); mdlModelItem_getData(pDgnIndexItem, &ctype, &is3D, NULL, NULL, NULL); ElDefRef = defHdler.FindByName((WCharCP)wCellName, *pDgnFile); if (ElDefRef != nullptr) break; } /*找到需要的模型后,查找该模型下参数化的单元,因为有前提条件和要求,所以可直接查找该模型下的参数化信息。*/ ParametricCellDefinitionPtr PaDef = defHdler.GetCellDefinition(ElementHandle(ElDefRef) ); //ParametricCellInfoPtr PaInfo = ParametricCellInfo::Create(status, *PaDef, setName, *pDgnModel); IParameterDefinitionsPtr paramDefs = PaDef->GetParameterDefinitions(); VirtualCollectionIterator<IParameterDefinitionsIterator> iterEnd = paramDefs->end(); for (VirtualCollectionIterator<IParameterDefinitionsIterator> iter = paramDefs->begin(); iter != iterEnd; ++iter) { //ECValue val1; //mdlDialog_dmsgsPrint( (*iter).GetDisplayLabel() ); WCharCP ddd = (*iter).GetDisplayLabel();//变量名称 WCharCP fff = (*iter).GetAccessString();//变量值 //ParameterType rtt = (*iter).GetType();//变量类型 mdlDialog_dmsgsPrint(WPrintfString(L"名称:%s 内容:%s ", ddd, fff )); }
前一种方法是自己写程序解析ECClass、ECProperty、ECInstance里边的内容,因为承载参数化单元参数值的ECClass结构非常复杂,解析起来非常麻烦,所以SDK又封装了一层接口,接口在后头已经完全处理好了调用起来相对简单多了。EC是基于XAttribute的,如果您没使用或者了解过XAttribute的话确实不好理解EC。通过XAttribute往元素上存储数据时,需要先定义一个c/c++的结构体,然后实例化一个对象实例,最后把这个实例挂到元素上边,这个属性会通过你自己程序中定义的一个ID值来区别于其他的XAttribute。读取的时候通过这个ID值来获取,想想一下如果只有这个ID值,而没有c/c++结构体的定义,获取XAttribute时返回了一个指针,程序中你怎么解析这个指针指向的内存区域呢?你完全解析不出来,所以为了方便业务数据在不同专业之间的交流,诞生了EC。通过EC存储属性的话,定义数据结构时不再是像XAttribute那样,声明一个c/c++的结构体,而是在一个xml中定义一个ECClass(可以参考C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\ECSchemas\Dgn这个路径下的xml文件),往元素上挂接ECInstance的时候,这个ECClass的内容也会保存到dgn文件中。这个时候其他人在读取你通过EC机制添加的属性时,后台会在dgn文件中找到对应的ECClass,随后当然也能解析出你添加的属性了。
我帮你写了一个简化版本的。需要知道这个参数集首先是一个数组,每个数组元素又是一个结构体。所以,用EC编起来比较复杂。你的代码取的不是放入模型中的参数化单元的参数集,而是参数化单元定义的参数集,这两个不是一会事儿。
【注】:WriteToXmlFile是为了让我们方便理解这个参数集数据而调用的,实际上是不需要的。
void extractParametricCellVariables(WCharCP) { ElementHandle eh(3044L, ACTIVEMODEL); if (!eh.IsValid()) { mdlDialog_dmsgsPrint(L"Element is invalid"); return; } ParametricCellHandler* pHandler = dynamic_cast<ParametricCellHandler*>(&eh.GetHandler()); if (nullptr == pHandler) { mdlDialog_dmsgsPrint(L"Element is not a parametric cell element"); return; } ParameterStatus status; ParametricCellInfoPtr pInfo = pHandler->GetCellInfo(status, eh); if (ParameterStatus::Success != status) { mdlDialog_dmsgsPrint(L"Fail to get parametric cell information"); return; } IECInstanceR inst = pInfo->GetProperties(); inst.WriteToXmlFile(L"D:\\PCInfo.XML", true, true); //Open this XML file to learn more about this complex instance ECPropertyIterable properties = inst.GetClass().GetProperties(); ECPropertyCP pProp = *properties.begin(); ECValue v; inst.GetValue(v, pProp->GetName().data()); ArrayInfo ai = v.GetArrayInfo(); // array of structures, first to get array for (uint32_t i = 0; i < ai.GetCount(); i++) { ECValue label, value; inst.GetValue(v, pProp->GetName().data(), i); IECInstancePtr pInst2 = v.GetStruct(); // then get strucuture pInst2->GetValue(label, L"Adhoc_Label"); pInst2->GetValue(value, L"Adhoc_Value"); WPrintfString wStr(L"PropertyLabel:%s, Value:%s", label.GetString(), value.GetString()); mdlDialog_dmsgsPrint(wStr); } }
Answer Verified By: 平凡人生
老师好:
您说的 模型中的参数化单元的参数集 :指的是从cell lib库中 申请下来,放置到dgn文件中的 cell 实例的意思吗?
参数化单元定义的参数集: 指的是 我们在定义参数化单元 的时候,添加的 参数属性吗?
还是 应该怎么理解?
谢谢老师的解答!!!!
当我们放置一个参数化单元时,会首先在当前文件中生成一个隐藏的模型,该模型来自于参数化单元库中对该单元的定义。我们看到的每个参数化单元元素都是对该定义的一个引用(或者叫实例)。在隐藏的那个定义模型中有一套参数集,在我们能看到的每个参数化单元实例上也有一套参数集。
Celltest4-chengtai.cel
我测试了 您的代码,发现 生成的xml 文件 已经存在我想要的参数(属性)了,但是,并没有打印出来,也就是说 没有再数组里面哪些参数。
另外,经过测试我发现
ECPropertyIterable properties = inst.GetClass().GetProperties(); ECPropertyCP pProp = *properties.begin(); ECValue v; inst.GetValue(v, pProp->GetName().data()); ArrayInfo ai = v.GetArrayInfo(); // array of structures, first to get array
代码中 pProp->GetName().data() 的返回值 为Name ,ai.GetCount()返回值为0。
是不是说明,我的参数 没有 再 数组里面?
不知道你是如何测试的。我这里测试的结果如下:
之所以我们显示的属性对比较多,是因为我们将隐藏的所有属性对都显示出来了。
是不是 我的 cell 文件 在定义 参数化cell 的时候 有问题, 老师 辛苦您一下, 看一下 我给您传的文件。0636.Celltest4-chengtai.cel
你的参数化单元定义是否引用了ItemType?我看到如下内容:
对于这种复杂的情况,还得再增加一个过滤,我简化的代码直接取的是properties.begin()
改进后的代码如下:
void extractParametricCellVariables(WCharCP) { ElementHandle eh(3090L, ACTIVEMODEL); if (!eh.IsValid()) { mdlDialog_dmsgsPrint(L"Element is invalid"); return; } ParametricCellHandler* pHandler = dynamic_cast<ParametricCellHandler*>(&eh.GetHandler()); if (nullptr == pHandler) { mdlDialog_dmsgsPrint(L"Element is not a parametric cell element"); return; } ParameterStatus status; ParametricCellInfoPtr pInfo = pHandler->GetCellInfo(status, eh); if (ParameterStatus::Success != status) { mdlDialog_dmsgsPrint(L"Fail to get parametric cell information"); return; } IECInstanceR inst = pInfo->GetProperties(); inst.WriteToXmlFile(L"D:\\PCInfo.XML", true, true); //Open this XML file to learn more about this complex instance ECPropertyIterable properties = inst.GetClass().GetProperties(); for (ECPropertyIterable::const_iterator iter = properties.begin(); iter != properties.end(); ++iter) { ECPropertyCP pProp = *iter; if (!pProp->GetName().Equals(L"ParameterValuesContainer")) continue; ECValue v; inst.GetValue(v, pProp->GetName().data()); ArrayInfo ai = v.GetArrayInfo(); // array of structures, first to get array for (uint32_t i = 0; i < ai.GetCount(); i++) { ECValue label, value; inst.GetValue(v, pProp->GetName().data(), i); IECInstancePtr pInst2 = v.GetStruct(); // then get strucuture pInst2->GetValue(label, L"Adhoc_Label"); pInst2->GetValue(value, L"Adhoc_Value"); WPrintfString wStr(L"PropertyLabel:%s, Value:%s", label.GetString(), value.GetString()); mdlDialog_dmsgsPrint(wStr); } } }
执行结果如下: