第4章、给Addins添加命令


Addins和NativeCode类似,能支持键入命令。随着XML的流行,Addins中定义命令表不再使用MDL中的资源文件Table的格式,而是采用XML格式来定义。本章的主要内容之一就是详细介绍XML命令表的格式。其次,还要介绍如何将命令表嵌入Addin程序中以及在Addin程序中如何写处理命令的方法。

下面就一个具体的XML格式的命令表进行分析说明。该命令表来自Mstn SDK中的…\Bentley\MicroStationCONNECTSDK\examples\Elements\ManagedFenceExample\commands.xml。每个命令表中有且仅有一个KeyinTree节点,其下会有三个部分组成,分别为RootKeyinTable、SubKeyinTables和KeyinHandlers,它们分别表示命令的根键入表、子键入表以及命令键入对应的处理函数名称。

 

<?xml version="1.0" encoding="utf-8" ?>
<KeyinTree xmlns="http://www.bentley.com/schemas/1.0/MicroStation/AddIn/KeyinTree.xsd">

    <RootKeyinTable ID="root">
        <Keyword SubtableRef="Commands" CommandWord="FENCEEXAMPLE">
            <Options Required="true" />
        </Keyword>
    </RootKeyinTable>

    <SubKeyinTables>
        <KeyinTable ID="Commands">            
            <Keyword SubtableRef="FromCmd" CommandWord="FROM">
                <Options Required="true" />
            </Keyword>
          <Keyword SubtableRef="ModifyCmd" CommandWord="MODIFY">
            <Options Required="true" />
          </Keyword>
          <Keyword CommandWord="CLEAR">
            <Options Required="true" />
          </Keyword>
        </KeyinTable>

        <KeyinTable ID="FromCmd">
          <Keyword CommandWord="ELEMENT" />
          <Keyword CommandWord="POINTS" />
        </KeyinTable>

      <KeyinTable ID="ModifyCmd">
        <Keyword CommandWord="MOVE"/>
        <Keyword CommandWord="CLIP"/>
        <Keyword CommandWord="STRETCH"/>
      </KeyinTable>

    </SubKeyinTables>

    <KeyinHandlers>
        <KeyinHandler Keyin="FENCEEXAMPLE FROM ELEMENT"            Function="ManagedFenceExample.Keyin.CmdPlaceFenceFromElement"/>
        <KeyinHandler Keyin="FENCEEXAMPLE FROM POINTS"             Function="ManagedFenceExample.Keyin.CmdPlaceFenceFromPoints"/>
        <KeyinHandler Keyin="FENCEEXAMPLE CLEAR"                   Function="ManagedFenceExample.Keyin.CmdClearFence"/>
        <KeyinHandler Keyin="FENCEEXAMPLE MODIFY MOVE"             Function="ManagedFenceExample.Keyin.CmdMoveFenceContents"/>
        <KeyinHandler Keyin="FENCEEXAMPLE MODIFY CLIP"             Function="ManagedFenceExample.Keyin.CmdClipFenceContents"/>
        <KeyinHandler Keyin="FENCEEXAMPLE MODIFY STRETCH"          Function="ManagedFenceExample.Keyin.CmdStretchFenceContents"/>      
    </KeyinHandlers>

</KeyinTree>

在<RootKeyinTable>和<KeyinTable>中有属性ID,表示该表的名称。命令表的内容由一个或多个<Keyword>元素组成,<Keyword>属性SubtableRef指向其下级命令表的ID。这样,通过当前表中<Keyword>的SubtableRef和下级表中<KeyinTable>的ID就能构成一个命令树。Mstn中的命令由一到五个单词组成,因而,我们在定义自己的commands.xml时在<SubKeyinTables>段中最多可以定义四级命令。<Keyword>还必须有属性CommandWord,这是用户在Mstn键入域中可输入的单词。<Keyword>有一个属性CommandClass表示该键入命令对应的命令类别,目前支持的命令类别有Placement、Viewing、Fence、Parameters、Locks、MacroCommand、Manipulation等。命令类别还可以是Inherit,表示继承上个命令单词所属的命令类别。<Keyword>中还可以包含<Options>项,该项是对<Keyword>的进一步说明,其属性有Required、Default、TryParse、Hidden等。Required="true"表示该命令字不是最后一个单词,必须有下级子节点;Default="true"表示该命令字为默认,当省略这一级命令字时取该命令字,在同一级别中只能有一个命令字为Default。TryParse="true"表示该命令字后可跟用户输入的任意字符,这些不在命令表中的字符串将被传递到命令处理函数的unparsed参数中。比如Active Color命令后可跟Red、Green、Blue等,也可以跟一个数字,如Active Color 245。我们不可能在命令表中列出每个这样的键入,此时可用TryParse属性;Hidden="true"表示该命令隐藏,用户在Mstn的命令浏览器中看不到该命令,但该命令仍然有效。这些隐藏的命令往往为程序所用或暂时不想对用户公开。
<KeyinHandlers>段只有<KeyinHandler>一种元素。其中的Keyin属性表示完整的键入命令字符串,<KeyinHandler>的Function属性为该键入命令对应的处理函数名,该函数名由命名空间名、类名和函数名(或称方法名)三部分组成。换句话说,当用户在Mstn中输入Keyin中的字符串时,就会调用到Function指定的函数。

下面我们来一步步改造csAddins使其支持键入命令。

1.在VS中打开您的csAddins项目,选菜单Project > Add New Item (当然也可以像以前我们介绍的那样,右击项目名称后在弹出的菜单中选择Add New Item),在出现的窗体中找到并选中XML File并在名称栏中输入commands.xml后点击Add按钮为当前工程添加一个空的XML文件。如下图所示:

2.将如下命令表内容复制并粘贴到您的commands.xml文件中。

<?xml version="1.0" encoding="utf-8" ?>
<KeyinTree xmlns="http://www.bentley.com/schemas/1.0/MicroStation/AddIn/KeyinTree.xsd">
  <RootKeyinTable ID="root">
    <Keyword SubtableRef="CreateElement"
            CommandClass="MacroCommand" CommandWord="csAddins" >
      <Options Required="true"/>
    </Keyword>
  </RootKeyinTable>
  
  <SubKeyinTables>
    <KeyinTable ID="CreateElement">
      <Keyword SubtableRef="Commands" CommandWord="CreateElement">
        <Options Required="true"/>
      </Keyword>
    </KeyinTable>
    <KeyinTable ID="Commands">
      <Keyword CommandWord="LineAndLineString1"> </Keyword>
      <Keyword CommandWord="LineAndLineString2"> </Keyword>
      <Keyword CommandWord="LineAndLineString3"> </Keyword>
      <Keyword CommandWord="ShapeAndComplexShape"> </Keyword>
      <Keyword CommandWord="TextString"> </Keyword>
      <Keyword CommandWord="Cell"> </Keyword>
      <Keyword CommandWord="Dimension"> </Keyword>
      <Keyword CommandWord="BsplineCurve"> </Keyword>
      <Keyword CommandWord="Cone"> </Keyword>
    </KeyinTable>
  </SubKeyinTables>
  
  <KeyinHandlers>
    <KeyinHandler Keyin="csAddins CreateElement LineAndLineString1"
        Function="csAddins.CreateElement.LineAndLineString1"/>
    <KeyinHandler Keyin="csAddins CreateElement LineAndLineString2"
        Function="csAddins.CreateElement.LineAndLineString2"/>
      <KeyinHandler Keyin="csAddins CreateElement LineAndLineString3"
          Function="csAddins.CreateElement.LineAndLineString3"/>
      <KeyinHandler Keyin="csAddins CreateElement ShapeAndComplexShape"
          Function="csAddins.CreateElement.ShapeAndComplexShape"/>
      <KeyinHandler Keyin="csAddins CreateElement TextString"
          Function="csAddins.CreateElement.TextString"/>
      <KeyinHandler Keyin="csAddins CreateElement Cell"
          Function="csAddins.CreateElement.Cell"/>
      <KeyinHandler Keyin="csAddins CreateElement Dimension"
          Function="csAddins.CreateElement.Dimension"/>
      <KeyinHandler Keyin="csAddins CreateElement BsplineCurve"
          Function="csAddins.CreateElement.BsplineCurve"/>
      <KeyinHandler Keyin="csAddins CreateElement Cone"
          Function="csAddins.CreateElement.Cone"/>
  </KeyinHandlers>
</KeyinTree>

3.在解决方案浏览器中右击commands.xml并选择Properties菜单打开属性窗体,设置Build Action (生成动作) 为 Embeded Resource (嵌入资源) 。这样,command.xml文件将会被嵌入到csAddins.dll中。如下图所示:

4.用Notapad++打开项目配置文件D:\Files\BentleyMstn\MstnCE\Addins\csAddins\csAddins\csAddins.csproj,找到“<EmbeddedResource Include="commands.xml" />”这一行改为如下内容:

<EmbeddedResource Include="Commands.xml">
          <SubType>Designer</SubType>
          <LogicalName>CommandTable.xml</LogicalName>
</EmbeddedResource>

【注】:修改这个csproj时,一定要取消<EmbeddedResource>标签行尾的那个/符号。该符号是对于无内容的XML标签的结束符。我们现在添加了<LogicalName>标签后就需要用单独的</EmbeddedResource>来结束了。

5.对MyAddins.cs进行两处修改:5a) 在class MyAddin行前增加AddIn属性定义,指定MdlTaskID;5b) 注释或删除掉Run函数的所有内容,仅留下return 0一行。修改后的类定义如下:

[AddIn(MdlTaskID = "csAddins")]
    internal sealed class MyAddin : AddIn
    {
        public static MyAddin Addin = null;

        private MyAddin(System.IntPtr mdlDesc) : base(mdlDesc)
        {
            Addin = this;
        }

        protected override int Run(string[] commandLine)
        {
            return 0;
        }
    }

6.修改CreateElement.cs中的每个函数的说明,使其带有一个string类型的参数。如:

//用户可以在key-in命令后边以空格为分割符加一些字符串来传递一些额外的信息,此字符串作为命令函数的参数传递给函数
public static void LineAndLineString1(string unparsed)
{
……
}
public static void ShapeAndComplexShape(string unparsed)
{
……
}

7.在VS中生成项目,然后切换到Mstn装载csAddins程序集(详细步骤可参见前几章的介绍)。因为我们删除了MyAddins.cs中Run函数中的所有执行语句,所以,加载程序集后并没有绘出任何图形。

8.打开Key-in键入对话框,输入csaddins后会看到如下图所示的命令键入树,这与我们在commands.xml中的完全对应。此时输入其中的一个命令并回车就能绘出相应的一部分图形。如输入csaddins createelement cone将只会绘出如下图形:

通过以上练习您已经掌握了如何给Addin应用程序添加命令,CE之前的SDK中有一个检查命令表XML文件正确性的工具UstnXOM.exe。有关此工具的使用介绍可参考Learning MicroStation Addins Step by Step[4] 

在CE下,可参考如下文章来及时检验该命令XML文件语法的合法性:

自动检查Addin程序中XML格式命令表语法