C#进行Visio二次开发

工作总想偷懒,偷懒的前提就是要勤奋,那才有偷懒的资本

---------------------------------------------------------------------------------------------

   

Visio的编程对象模型

   

  Visio二次开发中,对于其对象模型的了解,就写我们吃饭用筷子一样重要,否则不熟悉筷子的使用场景和方法,是吃不到东西的。

   

  其中主要的是下面几个对象: 

   

  Application

   

  Window (Application.ActiveWindow)

   

  Document (Application.ActiveDocument)

   

  Master、Shape、Cell

   

  一个程序中,就只有一个Application对象,类似进程的概念;打开的Visio文件有很多窗口,有一个ActiveWindow的主窗口,选区窗口、形状窗口等;模具文件打开后也是一个Document、打开的Visio文件也是一个Document、ActvieDocument是指当前 Visio窗口对应的文档,每个Visio的Document有一个或者多个Page,如系统中有两个Page、一个为绘图Page,一个为背景 Page。

   

  模具文件里面有很多Master,Master类似于模板的概念,一个Master代表一个设备类型、Shape是定义一个图形的信息,模具里面的 Master有且只有一个Shape,每个Shape又有很多Cell,代表一个ShapeSheet里面的一个格子,每个格子都有一个唯一的引用名称的。

   

  Visio文档里面,和模具文件不同,里面一个大千世界,有很多Master,也很多Shape和Cell,但是由于我们看到图纸可能一个模具的设备会有拷贝多个,因此它们公用一个Master,也就是一个Master有多个Shape引用,我们分析文件,就知道里面有一个MasterID,有点像数据库里面的外键一样。

在VisioSDK中,大量提及使用Cell,CellsSRC等等方式进行操作,但却基本没有提及Visio的形状大小、颜色等等。Cell,Row,Column,比如最开始设置一个形状数据,为啥是取自CellsSRC(VisSectionProperty,0,0)第0行第0列?

把Visio保存成为XML后,发现每一个形状都是使用XML进行描述的。这很重要,也就是说,Cell代表了XML中的一个叶子节点。比如形状数据中的值等等。根据保存的值,一个形状数据有很多属性,一个"CUSTID1"就有这么多内容:

<Prop NameU='Row_1' ID='1'>

<Value Unit='STR'>CUSTID1</Value>

<Prompt F='No Formula'/>

<Label>ID</Label>

<Format F='No Formula'/>

<SortKey F='No Formula'/>

<Type>0</Type>

<Invisible F='No Formula'>0</Invisible>

<Verify F='No Formula'>0</Verify>

<LangID>1033</LangID>

<Calendar F='No Formula'>0</Calendar>

</Prop>

我们取得的Value这个Cell来定位Shape的。我们还可以取这个CUSTID1的Prompt,只需要用CellsSRC(VisSectionProperty,0, visCustPropsPrompt),注意,其实VisCustPropsPrompt的值是1,visCustPropsLabel的值是2。这暗示了一件事,也就是说,Column,列,意味着在XML中的位置,比如我们看到Value 是Prop中的第一行,哪么,它对应的Column就是0,我们数到Type是第6行,对应的Column就是5,这是真的吗?当然,不信去查visCustPropsType,它就是5。

哪么Row又是怎么回事呢?Row,在这里就是第几个Prop的意思。一个形状可以定义多个形状数据,哪么第一个形状数据就是Row 0,第二个就是Row1。这个可以用来枚举的。

哪么第一个参数Section是啥意思呢?因为我们是取形状数据,也就是CustProperty,因此第一个参数我们用的是visSectionProp。

XML里边一个Shape可以有好多好多类的Section,Prop只是其中之一而已。

   

言归正传,我们要设置Shape的位置,我们根据保存的XML可以很容易看出,Shape的位置信息似乎是在XForm这个Section里边的。

<XForm>

<PinX>1.771653543307088</PinX>

<PinY>10.23622047244095</PinY>

<Width>0.78740157480315</Width>

<Height>0.78740157480315</Height>

<LocPinX F='Inh'>0.393700787401575</LocPinX>

<LocPinY F='Inh'>0.393700787401575</LocPinY>

<Angle F='Inh'>0</Angle>

<FlipX F='Inh'>0</FlipX>

<FlipY F='Inh'>0</FlipY>

<ResizeMode F='Inh'>0</ResizeMode>

</XForm>

按照我们一般的思想,Shape总归有一个左上角的坐标,其实我没找到。PinX、PinY,是旋转的中心点。LocPinX和LocPinY是这个Shape自身的中心点。后来我想啊想啊的就想明白了,Shape(形状)可能是不规则的,虽然可以获得包容Shape的最小矩形框,但是毕竟不是规则的,也就是说,可能没有左上角的含义。所谓Shape中心点,也就是以左上角定义的中心点。(真的是左上角坐标系吗?呵呵)

实际上,Visio采用的坐标系是左下角坐标系,也就是说,以页面左下角为0,0,页面左上端为0,MaxY,页面右上端是MaxX,MaxY。

   

Ok,移动一个Shape,也就是设置<XForm>的<PinX>和<PinY>就可以了。根据上边我们对Cell的理解,也就是设置PinX,PinY这两个Cell就可以了。

get_CellsSRC的三个参数怎么填写呢?首先是Section节,Visio没有对XForm定义单独的Section,它把它归在了VisSectionIndices.visSectionObject中,也就是说Section是Object,它需要使用Row来确定是取XForm节,我猜了一下,是(short)VisRowIndices.visRowXFormOut节。其实还有一个,叫visRowXFormIn。visRowXFormOut、visRowXFormIn这两个参数定义都是0,为啥呢?因为<XForm>是<Shape>的第一个定义,按照Visio的Cell、Row、Column的参数定义,第一个就是0嘛。

第三个参数Column就很简单,取PinX就填写0,取PinY就填写1,实际上VisioSDK的参数中也是这样定义的,visXFormPinX = 0visXFormPinY = 1

看起来似乎一切正常。我们取得了表示位置中心的PinX和PinY Cell,只需要动动小手指,改一下这两个Cell的值,就可以搞定移动了。根据我们前边的知识,只需要设置Formula(汗死…)就可以了。

实际上我第一次也这样干的,傻呗。正确的做法是使用set_Result,get_Result,如下所示:

m_Cell = sp.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowXFormOut,

(short)VisCellIndices.visXFormPinX);

m_Cell.set_Result(VisUnitCodes.visCentimeters, m_Cell.get_Result(VisUnitCodes.visCentimeters) + DeltaX);

m_Cell = sp.get_CellsSRC((short)VisSectionIndices.visSectionObject, (short)VisRowIndices.visRowXFormOut,

(short)VisCellIndices.visXFormPinY);

m_Cell.set_Result(VisUnitCodes.visCentimeters, m_Cell.get_Result(VisUnitCodes.visCentimeters) + DeltaY);

posted @ 2012-09-12 08:54  宁#宁  阅读(2195)  评论(0编辑  收藏  举报