[MSCE C++]读取参数化cell参数的问题

 如图所示:我才用代码读取 某一个参数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;
}

Parents
  • 测试过了,我编写的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 ));
    	}

    Bentley 二次开发小白一枚

  • 前一种方法是自己写程序解析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 实例的意思吗?

                参数化单元定义的参数集:           指的是 我们在定义参数化单元 的时候,添加的 参数属性吗?

    还是 应该怎么理解?

    谢谢老师的解答!!!!

    Bentley 二次开发小白一枚

  • 当我们放置一个参数化单元时,会首先在当前文件中生成一个隐藏的模型,该模型来自于参数化单元库中对该单元的定义。我们看到的每个参数化单元元素都是对该定义的一个引用(或者叫实例)。在隐藏的那个定义模型中有一套参数集,在我们能看到的每个参数化单元实例上也有一套参数集。



    Answer Verified By: 平凡人生 

Reply
  • 当我们放置一个参数化单元时,会首先在当前文件中生成一个隐藏的模型,该模型来自于参数化单元库中对该单元的定义。我们看到的每个参数化单元元素都是对该定义的一个引用(或者叫实例)。在隐藏的那个定义模型中有一套参数集,在我们能看到的每个参数化单元实例上也有一套参数集。



    Answer Verified By: 平凡人生 

Children
  • 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。

    是不是说明,我的参数 没有 再 数组里面?

    Bentley 二次开发小白一枚

  • 不知道你是如何测试的。我这里测试的结果如下:

    之所以我们显示的属性对比较多,是因为我们将隐藏的所有属性对都显示出来了。



  • 是不是 我的 cell 文件 在定义 参数化cell 的时候 有问题, 老师  辛苦您一下, 看一下 我给您传的文件。0636.Celltest4-chengtai.cel

    Bentley 二次开发小白一枚

  • 你的参数化单元定义是否引用了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);
    		}
    	}
    }

    执行结果如下:



    Answer Verified By: 平凡人生