1. Provider类的基本原理
此类最主要的功能就是注册与反注册。这里介绍一下注册与反注册的具体流程。
如图所示我们的Provider类的最主要的功能就是注册与注销。在以上步骤中我们注册SchemaName是最关键的一步。它起到的作用是把我们的SchemaName通过函数SetPreviewDgnForTargetType设置到AnnotationManager中。AnnotationManager是我们所有Annotation的底层管理类,我们所有的Enabler、Evaluator、Provider都是通过此类建立了彼此之间的联系。
下面就谈一下我的SchemaName到底起到什么样的作用了,具有相同SchemaName的Annotation可以认为是一类AnnotationDefinition。此处说的AnnotationDefinition在界面上(OpenRoads Standards-Annotation Definitions)的树形菜单中按照注册的类型进行分组。如下图所示:
同样的,具有相同的SchemaName的AnnotationDefinition,也具备以下特征:具有相同的属性列表(属性值可以不同),如下图所示。
综上所述Provider类的主要作用就是起注册作用,注册一个名称为SchemaName类型,再通过AnnotationManager类把注册的SchemaName与属性绑定并管理起来。
明确了Provider类的功能现在我们有会有疑问,我们上面所说的属性又是哪个类来管理的呢,这里该提到我们的 MyAnnotationEnabler类。
2. Enabler类的基本原理
上面提到了我们的Enabler类的最主要的作用就是做为存储类。但它在整体中的地位又是什么呢?它什么时候被调用,程序又是怎么找到MyAnnotationEnabler的呢?Enabler类又能存储哪些数据呢?
我们带着以上问题,查看示例可以看到一些端倪。
我们的示例中包含有Provider 、Enabler、Evaluator等三个最主要的类。Enabler类起到一个承上启下的作用,保存数据为我们后面Annotation的绘制起到数据仓库的作用。
在ORD中关于Provider 、Enabler的关系,AnnotationManager起到了至关紧要的作用。当我们的注册Provider的时候,注册Enabler的发动机已经开启。
即在示例中当我们在MyAnnotationProvider的Initialize() 函数中调用以下注册语句时AnnotationManager::GetManager().RegisterProvider(*this);
这时候Enabler中调用了_GetECClassName()、_GetECClassDisplayName()、_AddProperties()等主要函数。这时候Enabler有了名称、显示名称和应有的属性。显示名称在我们界面中作为标示一个AnnotationDefinition的名称属性显示。
这时大家又会有疑问,为什么MyAnnotationProvider注册的时候去调用MyAnnotationEnabler的呢?答案就在以下一段代码中:
void MyAnnotationProvider::_CollectEnablers(bvector<AnnotationEnabler*>& enablers) const
{
enablers.push_back(&MyAnnotationEnabler::GetInstance());
}
这里_CollectEnablers 函数为虚函数,这时大家就明白为什么MyAnnotationProvider类与MyAnnotationEnabler类能对应上了吧!
我们知道了Enabler类的地位以后,我们再看下这个类又能存储哪些数据。在Enabler的基类AnnotationBaseEnabler中我们可以看到有以下函数 :
AddBoolProperty(WCharCP categoryName, int category, int priority, WCharCP propertyName, WStringCR propertyDisplay, bool defaultValue) const;
AddIntegerProperty(WCharCP categoryName, int category, int priority, WCharCP propertyName, WStringCR propertyDisplay, int defaultValue) const;
AddDoubleProperty(WCharCP categoryName, int category, int priority, WCharCP propertyName, WStringCR propertyDisplay, double defaultValue) const;
AddStringProperty(WCharCP categoryName, int category, int priority, WCharCP propertyName, WStringCR propertyDisplay, WCharCP defaultValue) const;
AddTextStyleProperty(WCharCP categoryName, int category, int priority, WCharCP propertyName, WStringCR propertyDisplay, int defaultValue) const;
AddStandardExtendedTypeProperty(WCharCP categoryName, int category, int priority, WCharCP propertyName, WStringCR propertyDisplay, ECN::PrimitiveType ecType, Bentley::DgnPlatform::DgnECExtendedType::StandardType extendedType) const;
我们最基本的数据存储在底层都有对应的函数。我们可以直接存储布尔、整型、浮点型等类型的参数。
下图为Provider 、Enabler的关系图:
3. Evaluator类的基本原理
终于要谈到我们的主角MyAnnotationEvaluator了。之所以称它为主角,是因为我们的Annotation所有的元素都是由它来绘制的。我们的MyAnnotationEvaluator看起来很复杂其实最关键的功能就是绘图(在我们的_Draw()函数中)。
其它函数基本上都是辅助我们进行绘图,但这里还有以下几点需要注意的地方。
我们要对哪些元素进行标注,这个函数为我们提供了要标注的对象:
AlignmentPtr GetAlignment()
return Alignment::CreateFromDgnElementECInstance(GetAnnotatedInstance());
我们标注元素所需要的属性值在来自哪里呢,我们从下面的函数可以看出来龙去脉:
double GetLineLength()
double val;
if (SUCCESS == GetDoubleValueParameter(val, L"Length"))
return val;
return 0.0;
这里的函数是不是和AddDoubleProperty挺像的,其实它们是一个写数据的函数,一个是取数据的函数,它们是一一对应的。更底层的存取是通过ECFormwork来实现的。对底层有兴趣的可以去查阅ECFormwork方面的资料。
现在大家又会有一个疑问,这里的Evaluator和Enabler是怎么关联的呢,我们通过以下函数可以看出:
AnnotationEvaluatorPtr MyAnnotationEnabler::_CreateEvaluator() const
return MyAnnotationEvaluator::Create();
};