部分在OPM中获取接口获取到属性的DisplayLabel和属性类别的DisplayLabel和OPM界面上显示的不一致。
在OPM界面上显示的是label经过了本地化,而通过接口获取的数据却没有本地化。
在显示时在同一类别的四条属性,通过接口获取有两条得到的类别显示标签是没有本地化的数据。
同时四条数据的显示标签都没有本地化。
OPM: 10.10.00.72 简体中文版
Workspace:OpenPlantExample
WorkSet:Metric
DGN:C:\ProgramData\Bentley\OpenPlant CONNECT Edition\Configuration\WorkSpaces\OpenPlantExample\WorkSets\Metric\WorkFiles\Models\Modeler\BT-3D-01-ALL.dgn
使用的示例项目以及修改的文件为:
C:\Program Files\Bentley\OpenPlant CONNECT Edition\OpenPlantModeler\SDKExamples\PipingExample\Keyins.cs
修改的函数和代码行如下:
public static void Example1(System.String unparsed) { ECInstanceList list = DgnUtilities.GetAllInstancesFromDgn(); IECClass EQUIPMENT = SchemaUtilities.GetClassInPlantSchema("EQUIPMENT"); string resultMessage = ""; foreach (var i in list) { IECClass c = i.ClassDefinition; if (c.Is(EQUIPMENT)) { IECProperty NAME = c.FindProperty("NAME"); IECProperty PLANT_AREA = c.FindProperty("PLANT_AREA"); IECProperty DEVICE_TYPE_CODE = c.FindProperty("DEVICE_TYPE_CODE"); IECProperty NUMBER = c.FindProperty("NUMBER"); string category = PLANT_AREA.GetCustomAttributes("Category").GetPropertyValue("DisplayLabel").StringValue; resultMessage += category + "/" + NAME.DisplayLabel + "\n"; resultMessage += category + "/" + PLANT_AREA.DisplayLabel + "\n"; resultMessage += category + "/" + DEVICE_TYPE_CODE.DisplayLabel + "\n"; resultMessage += category + "/" + NUMBER.DisplayLabel + "\n"; } } MessageCenter.SendInfoMessage("Result Message: ", resultMessage); }
编译之前需要添加两个引用:
C:\Program Files\Bentley\OpenPlant CONNECT Edition\OpenPlantModeler\Assemblies\ECFramework\Bentley.ECObjects3.dll
C:\Program Files\Bentley\OpenPlant CONNECT Edition\OpenPlantModeler\Assemblies\ECFramework\Bentley.Platform.dll
KeyIn:
mdl load pipingexample pipingexample example1
4.1、WorkSet需要完成了本地化,也就是说需要有大概如下的本地化文件:
4.1.1、在这些文件中搜索您想要的中文字符串,如果没有,则说明本地化未完成
4.2、保证当前线程的Culture为简体中文
对应到.NET应该是zh-CN,简中在.NET中有多个名字,我也没有研究过具体的区别。
最简单的办法是,将操作系统的Region设置为中文(简体,中国),语言设置为简体中文,并且使用OPM的简体中文版。
4.3、保证OPM补充了本地化补充Schema,也就是上图列出的几个Schema文件
在最基础的ECAPI中,这件事可能需要手工做。
(Supplemental Schema的存在让主schema有两种状态:未补充过的和补充过的)
不过我觉得OPM的如下API应该考虑了这个问题,所以尽量用这个或者其他的OPM API来获得要遍历的实例列表,而不是用最基础的MS和EC API:
ECInstanceList list = DgnUtilities.GetAllInstancesFromDgn();
如果您使用Class Editor或其它工具修改过DisplayLabel,则情况会更复杂一些,复杂性来源于默认保存位置,具体机制需要进一步分析。
Answer Verified By: George
谢谢老师回复,根据老师您的步骤我确实能够获取到本地化之后的数据。
我看您在4.3中提到要保证OPM补充了本地化补充Schema。而我获取的数据不对的原因,应该就是通过c++的接口得到的schema是没有补充过的。
请问老师有没有C++补充schema的接口呢?
OPM的接口都是.NET的,我也没有用过相应的MS SDK C++接口,不过我猜可能是这个:SupplementedSchemaBuilder
但这里需要有个技术框架上的考虑:
1、这样构建出来的这个Schema是属于你的程序的,而不是OPM的,进一步说,就是OPM加载的跟你加载的内容范围可能不匹配,就会导致OPM API和您调用的MS API查询到的东西不一致的情况。
2、假如说OPM在处理这些Schema加载时有触发某种回调(或者它将来打算这么做),但我并没找到一种机制能够保证在现在以及将来您的程序在加载和补充Schema的时候也可以触发这种回调,这也可能会导致行为不一致的情况出现。这是另一个风险点。
这两个问题其实是小问题,但会很费时间去调试和分析。
基于以上,我推荐的思路是:用OPM的API处理OPM的问题。
如果想在C++调用,可以考虑两个思路:
1、用C++/CLI、P/Invoke等互操作机制,就是可能需要在本地指针和.NET 引用之间来回转换。
2、只封装DgnUtilities.GetAllInstancesFromDgn()这个接口给C++调用,C++调用之后保存着这个列表先不要释放,这个列表就作为一个资源的Handle,其它什么都不做,之后用一般的C++API去获取实例列表和遍历,理论上应该也能取到所有的东西,取完之后再释放列表。因为我们拿着这个Handle,所以OPM在此期间应该不会释放补充的Schema。
3、还是2的思路,但可以尝试做两个C#的Keyin给OPM用,一个是加载列表,这时候将得到的实例列表保存在一个全局变量,还有一个是释放列表,这个Keyin在C++处理完成之后调用,释放实例列表,这样就不需要任何互操作了,通过Keyin解耦。
好的,谢谢老师回复。