技术开发 频道

VS与Win7共舞:用XML文件定义Ribbon界面

  【IT168 专稿】在上一篇文章中,我们介绍了如何利用Windows Scenic Ribbon API为一个普通的Windows应用程序添加Ribbon界面。其中,我们只是简单地添加了一个Ribbon面板和一个按钮控件,还没有实现任何的具体功能。这就像我们创建了一个Ribbon容器,等着我们将各种Ribbon控件装进去并对控件的各种消息进行处理,以实现相应的业务逻辑。

  在这一篇文章中,我们就来介绍如何向Ribbon面板添加各种Ribbon控件并实现控件的合理排布。

  微软在自己大量用户体验研究的基础上,同时积极汲取用户对第一代Ribbon界面的反馈,在第二代Scenic Ribbon界面中,提供了更加丰富的Ribbon控件,使得Ribbon界面的控件更加丰富。通过这些Ribbon控件的灵活组合应用,能够应对各种应用程序对Ribbon界面控件的需要。下面我们就来介绍一下如何为Ribbon界面添加各种Ribbon控件并对这些控件进行排列布局。

  添加Ribbon界面添加应用程序菜单

  除了Ribbon面板,Ribbon界面的最大革新之处就是它的应用程序菜单。在Ribbon界面中,我们可以在Ribbon面板上布置一些常用的命令功能,而对于一些不太常用的功能,比如文件打开关闭,系统设置等等,都可以在应用程序菜单中进行。Ribbon界面中应用程序菜单的定义非常简单,跟添加按钮控件相似,我们需要先在XML文件的命令部分添加菜单中需要的各个菜单项:
 

<!—应用程序菜单项-->
    
<Command Name="FileMenu"
             Symbol
="cmdFileMenu"
             Id
="25000" />
    
<!—为最长使用文档列表定义控件 -->
    
<Command Name="cmdMRUList"
             Symbol
="cmdMRUList"
             Id
="25050"/>
    
<Command Name="cmdMRUItems"
             Symbol
="cmdMRUItems"
             Id
="25051"/>
    
<Command Name="cmdNew"
             Symbol
="cmdNew"
             Comment
="New"
             Id
="25001"
             LabelTitle
="New">
        
<Command.LargeImages>
          
<Image Source="NewL.bmp"/>
        
</Command.LargeImages>
    
</Command>
    
<Command Name="cmdOpen"
             Symbol
="cmdOpen"
             Comment
="Open"
             Id
="25002"
             LabelTitle
="Open"/>
    
<Command Name="cmdSave"
             Symbol
="cmdSave"
             Comment
="Save"
             Id
="25003"
             LabelTitle
="Save"
             TooltipTitle
="Save tooltip title"
             TooltipDescription
="Save tooltip description."/>
    
<Command Name="cmdPrint"
             Symbol
="cmdPrint"
             Comment
="Print"
             Id
="25004"
             LabelTitle
="Print" />
    
<Command Name="cmdExit"
             Symbol
="cmdExit"
             Comment
="Exit"
             Id
="25005"
             LabelTitle
="Exit" />

  完成这些菜单项的定义后,我们就可以在视图部分将这些菜单项添加到应用程序菜单中,完成它的定义。编辑XML文件的视图部分,添加应用程序菜单:

<Ribbon>
        
<Ribbon.Tabs>
          
<!--... -->
        
</Ribbon.Tabs>
        
<!—添加应用程序菜单-->
        
<Ribbon.ApplicationMenu>
          
<ApplicationMenu CommandName="FileMenu">
            
<!—最常使用选项. -->
            
<ApplicationMenu.RecentItems>
              
<RecentItems CommandName="cmdMRUItems"/>
            
</ApplicationMenu.RecentItems>
            
<!—菜单项 -->
            
<MenuGroup Class="MajorItems">
              
<Button CommandName="cmdNew" />
              
<Button CommandName="cmdOpen" />
              
<Button CommandName="cmdSave" />
            
</MenuGroup>
            
<MenuGroup Class="StandardItems">
              
<Button CommandName="cmdPrint" />
              
<Button CommandName="cmdExit" />
            
</MenuGroup>
          
</ApplicationMenu>
        
</Ribbon.ApplicationMenu>
      
</Ribbon>

  现在我们编译解决方案,点击Ribbon界面左上方的应用程序图标,就可以看到新添加的应用程序菜单了。我们可以看到,最常使用列表还是空空如也,因为我们还没有打开过文件:


 

  为Ribbon界面添加按钮控件

  按钮控件可以说是我们最常用的控件了。在Ribbon界面中,按钮控件有多种形式,主要有普通按钮(Button),复选框(CheckBox),下拉按钮(DropDownButton)以及切换按钮(ToggleButton)等,可见为Ribbon界面添加按钮控件是我们对Ribbon界面进行设计的基本功。虽然Visual Studio 2010没有提供针对Scenic Ribbon界面编辑的可视化设计工具,但是通过对Ribbon界面XML文件的编辑来实现控件的添加和定义也十分简单。

  我们还是在上文例子的基础上,实现按钮控件的添加。我们可以打开Ribbon界面描述文件ribbonmarkup.xml,然后在其中的命令部分添加下面的语句,定义相应的按钮控件:

<Application.Commands>
    
<!--Tab页面-->
    
<Command Name="TabHome" Symbol="cmdTabHome" Id="30000" LabelTitle="主页" />
<!—按钮分组控件-->
    
<Command Name="GroupButton" Symbol="cmdGroupMain" Id="30001" LabelTitle="按钮控件"/>
    
<Command Name="NormalButton" Symbol="cmdNormalButton" Id="30002" LabelTitle="普通按钮">
      
<Command.TooltipTitle>普通按钮</Command.TooltipTitle>
      
<Command.TooltipDescription>这是一个普通按钮。</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="Button_Image.bmp"/>
      
</Command.LargeImages>
      
<Command.SmallImages>
        
<Image Source="Button_Image.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<Command Name="DropDownButton" Symbol="cmdDropDownButton" Id="30003" LabelTitle="下拉按钮">
      
<Command.TooltipTitle>下拉按钮</Command.TooltipTitle>
      
<Command.TooltipDescription>这是一个下拉按钮。</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="Button_ImageL.bmp"/>
      
</Command.LargeImages>
      
<Command.SmallImages>
        
<Image Source="Button_ImageS.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<Command Name="ToggleButton" Symbol="cmdToggleButton" Id="30004" LabelTitle="切换按钮">
      
<Command.TooltipTitle>切换按钮</Command.TooltipTitle>
      
<Command.TooltipDescription>这是一个切换按钮。</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="Button_ImageL.bmp"/>
      
</Command.LargeImages>
      
<Command.SmallImages>
        
<Image Source="Button_ImageS.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<Command Name="CheckBox" Symbol="cmdCheckBox" Id="30005" LabelTitle="复选框">
      
<Command.TooltipTitle>复选按钮Command.TooltipTitle>
      
<Command.TooltipDescription>这是一个复选按钮。</Command.TooltipDescription>
</Command>
</Application.Commands>

  在这里,我们定义了多种按钮控件:普通按钮,下拉按钮,切换按钮和复选框按钮。同时为了对这些按钮控件进行管理,我们还定义了一个组控件GroupButton。对于GroupButton,我们只是简单地给定了它的ID和符号。而对于NormalButton等按钮控件,我们通过XML文件,指定了这些按钮控件的具体属性,比如按钮的按钮上显示的文字,工具栏提示,按钮显示的图片等等。通过XML文件,我们可以对各个控件的属性进行详细的定义,完全根据我们的需要对控件进行自定义。

  完成控件的定义后,我们就可以将这些控件布局到Ribbon面板上了。继续在xml文件中的视图(View)部分编辑代码,实现各个控件的排布:

<Application.Views>
      
<Ribbon>
        
<Ribbon.Tabs>
          
<Tab CommandName='TabHome'>
            <Group CommandName='GroupButton' SizeDefinition='ThreeButtonsAndOneCheckBox'>
              <DropDownButton CommandName='DropDownButton'>
                <MenuGroup CommandName ='DownMenu'>
                  <Button CommandName ='NormalButton'/>
                  <ToggleButton CommandName='ToggleButton'/>
                </MenuGroup>
              
</DropDownButton>
              
<Button CommandName='NormalButton'/>
              <ToggleButton CommandName='ToggleButton'/>
              <CheckBox CommandName ='CheckBox'/>
            </Group>
          
</Tab>
        
</Ribbon.Tabs>
      
</Ribbon>
    
</Application.Views>

  在这段视图部分的XML代码中,我们可以很清楚地看到各个空间之间的嵌套关系:TabHome这个Tab页面包含一个GroupButton这个组,而这个组又包含DropDownButton,NormalButton,ToggleButton和CheckBox这几个子按钮控件。更进一步的,DropDownButton又包含了NormalButton和TonggleButton这两个子按钮控件。通过这种层层嵌套,我们就实现了各个子控件的布局。

  现在我们编译运行这个解决方案,就可以看到我们刚刚添加的Ribbon界面了:

  使用控件布局模板

  在上面的例子中,我们将多个按钮控件都添加到了一个组控件中。在这个组控件内部,各个按钮控件是按照怎样的规则进行布局的呢?能不能对默认的布局进行控制?

  为了对一个控件容器内部的各个控件进行布局,Scenic Ribbon提供了相应的布局模板。在一个控件容器,例如上文中我们用到的Group控件,对控件进行排布时,Scenic Ribbon会按照我们在XML文件中定义的布局模板来对控件进行排布。在XML中,我们使用SizeDefinition属性来定义容器所使用的布局模板,例如:

<Group CommandName='GroupButton' SizeDefinition='ThreeButtonsAndOneCheckBox'>

  这行代码就表示使用“'ThreeButtonsAndOneCheckBox'”作为这个组容器的布局模板,表示这个组内部一共有三个按钮和一个复选框。为了便于我们的使用,Scenic Ribbon为我们提供了很多已经预先定义好的布局模板,例如我们常用的有:

  处理这些预先定义的布局模板之外,针对一些特殊需要,我们还可以自定义布局目标,实现更加灵活的控制。例如,下面的代码简单地自定义了一个布局模板:

<!—自定义布局模板 -->
<Ribbon.SizeDefinitions>
          
<SizeDefinition Name="CustomTemplate">
            
<GroupSizeDefinition Size="Large">
              
<ControlSizeDefinition ImageSize="Large" IsLabelVisible="true" />
            
</GroupSizeDefinition>
            
<GroupSizeDefinition Size="Medium">
              
<ControlSizeDefinition ImageSize="Small" IsLabelVisible="false" />
            
</GroupSizeDefinition>
            
<GroupSizeDefinition Size="Small">
              
<ControlSizeDefinition ImageSize="Small" IsLabelVisible="false" />
            
</GroupSizeDefinition>
          
</SizeDefinition>
</Ribbon.SizeDefinitions>

<!—使用布局模板 -->
<Group CommandName='GroupButton' SizeDefinition='CustomTemplate'>
       <Button CommandName='NormalButton' />
</Group>

  在这个自定义布局模板中,我们定义了控件在不同显示状态(Large,Medium,Small)下,图标的尺寸和标签文本的显示与否。这样,我们就可以对控件的外观进行非常细致的控制,满足用户体验设计师的苛刻要求。

  设置控件的缩放策略

  在上文的自定义布局模板中,我们定义了控件在不同状态下的显示尺寸。当我们在缩放窗口的时候,Ribbon面板的尺寸会相应的改变,这时,Ribbon控件的尺寸和排布也会发生相应的变化。Ribbon控件的大小以及排布方式,都受到Tab页面控件缩放策略的控制。在Ribbon界面中,每个Tab页面都有独立的控件缩放策略,我们可以通过定义Tab页面的缩放策略来控制按钮的大小以及在面板尺寸发生变化时候,如何对控件进行重新排布。为了展示Tab页面缩放策略对控件尺寸和排布的控制,我们在Ribbon面板中在添加多个按钮,并实现不同的组使用不同的重排次序。

  首先我们在XML文件的命令部分(Commands)添加相应的控件描述:

<Application.Commands>
    
<!--Tab页面-->
    
<Command Name="TabHome" Symbol="cmdTabHome" Id="30000" LabelTitle="主页" />
    
<!--主要分组-->
    
<Command Name="GroupMain" Symbol="cmdGroupMain" Id="30001" LabelTitle="组控件"/>
    
<Command Name="MyButton" Symbol="cmdMyButton" Id="30002" LabelTitle="按钮控件">
      
<Command.TooltipTitle>按钮控件</Command.TooltipTitle>
      
<Command.TooltipDescription>点击这个按钮控件,获得当前系统时间。</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="Button_Image.bmp"/>
      
</Command.LargeImages>
      
<Command.SmallImages>
        
<Image Source="Button_Image.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<!--数据库组-->
    
<Command Name="GroupDatabase" Symbol="cmdGroupDatabase" Id="30004">
      
<Command.LabelTitle>Database</Command.LabelTitle>
    
</Command>
    
<!--数据库组按钮控件-->
    
<Command Name="AddTable" Symbol="cmdAddTable" Id="30006"
    LabelTitle
="Add Table">
      
<Command.TooltipTitle>Add Table</Command.TooltipTitle>
      
<Command.TooltipDescription>Add Table</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="AddTableL.bmp"/>
      
</Command.LargeImages>
      
<Command.SmallImages>
        
<Image Source="AddTableS.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<Command Name="DeleteTable" Symbol="cmdDeleteTable" Id="30007" LabelTitle="Delete Table">
      
<Command.TooltipTitle>Delete Table</Command.TooltipTitle>
      
<Command.TooltipDescription>Delete Table</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="DeleteTableL.bmp"/>
      
</Command.LargeImages>
      
<Command.SmallImages>
        
<Image Source="DeleteTableS.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<Command Name="PrintRelationships" Symbol="cmdPrintRelationships" Id="30008" LabelTitle="Print Relationships">
      
<Command.TooltipTitle>Print Relationships</Command.TooltipTitle>
      
<Command.TooltipDescription>Print Relationships</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="PrintRelationshipsL.bmp"/>
      
</Command.LargeImages>
      
<Command.SmallImages>
        
<Image Source="PrintRelationshipsS.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<!--剪切板组-->
    
<Command Name="GroupClipboard" Symbol="cmdGroupClipboard" Id="30005">
      
<Command.LabelTitle>Clipboard</Command.LabelTitle>
      
<!--定义剪切板组的图标,用于在剪切板处于Popup模式时显示-->
      
<Command.LargeImages>
        
<Image Source="Paste.bmp"/>
      
</Command.LargeImages>
    
</Command>
    
<!--剪切板组按钮控件-->
    
<Command Name="Paste" Symbol="cmdPaste" Id="30009" LabelTitle="Paste">
      
<Command.TooltipTitle>Paste</Command.TooltipTitle>
      
<Command.TooltipDescription>Paste</Command.TooltipDescription>
      
<Command.LargeImages>
        
<Image Source="Paste.bmp"/>
      
</Command.LargeImages>
    
</Command>
    
<Command Name="Cut" Symbol="cmdCut" Id="30010" LabelTitle="Cut">
      
<Command.TooltipTitle>Cut</Command.TooltipTitle>
      
<Command.TooltipDescription>Cut</Command.TooltipDescription>
      
<Command.SmallImages>
        
<Image Source="Cut.bmp"/>
      
</Command.SmallImages>
    
</Command>
    
<Command Name="Copy" Symbol="cmdCopy" Id="30011" LabelTitle="Copy">
      
<Command.TooltipTitle>Copy</Command.TooltipTitle>
      
<Command.TooltipDescription>Copy</Command.TooltipDescription>
      
<Command.SmallImages>
        
<Image Source="Copy.bmp"/>
      
</Command.SmallImages>
    
</Command>

  在上面的代码中,我们定义了控件的各种属性,现在要将这些控件布置到Ribbon面板上,则需要Tab页面的缩放策略来控制了。所以,我们在XML文件的视图部分对控件进行布置并设置缩放策略:

<Application.Views>
    
<Ribbon>
      
<Ribbon.Tabs>
        
<Tab CommandName="TabHome">
          
<!--定义Tab页面的缩放策略-->
          
<Tab.ScalingPolicy>
            
<ScalingPolicy>
              
<!--定义在默认情况下的控件尺寸。
              在通常情况下,应用程序启动后都处于尺寸最大的状态,
              所以在这里,都默认使用大尺寸
-->
              
<ScalingPolicy.IdealSizes>
                
<Scale Group="GroupMain" Size="Large"/>
                
<Scale Group ="GroupDatabase" Size="Large"/>
                
<Scale Group ="GroupClipboard" Size="Large"/>
              
</ScalingPolicy.IdealSizes>
              
<!--这里定义了Ribbon面板缩放时,Ribbon控件缩放的次序
              比如,当窗口缩小,Ribbon面板跟着缩小时,GroupDatabase组
              的按钮将首先缩小为Medium类型,其次GroupClipboard组缩小
              为Medium类型,以此类推
-->
              
<Scale Group ="GroupDatabase" Size="Medium"/>
              
<Scale Group ="GroupClipboard" Size="Medium"/>
              
<Scale Group ="GroupClipboard" Size="Popup"/>
              
<Scale Group ="GroupMain" Size="Medium"/>
            
</ScalingPolicy>
          
</Tab.ScalingPolicy>

          
<!--定义控件的嵌套关系
          我们使用组的SizeDefinition属性定义组内控件的排布方式
-->
          
<Group CommandName="GroupMain" SizeDefinition="TwoButtons">
            
<Button CommandName="MyButton"/>
            
<Button CommandName="AddTable"/>
          
</Group>
          
<Group CommandName="GroupDatabase" SizeDefinition="ThreeButtons">
            
<Button CommandName="AddTable"/>
            
<Button CommandName="DeleteTable"/>
            
<Button CommandName="PrintRelationships"/>
          
</Group>
          
<Group CommandName="GroupClipboard" SizeDefinition ="BigButtonsAndSmallButtonsOrInputs">
            
<ControlGroup>
              
<Button CommandName="Paste"/>
            
</ControlGroup>
            
<ControlGroup>
              
<Button CommandName="Cut"/>
              
<Button CommandName="Copy"/>
            
</ControlGroup>
          
</Group>
        
</Tab>
      
</Ribbon.Tabs>
    
</Ribbon>
  
</Application.Views>

  在这段代码中,通过Tab页面TabHome的缩放策略,我们首先定义了各个控件组在默认情况下的显示排布状态。在窗口足够大,Ribbon界面能够完全显示的情况下,Ribbon界面中的控件将按照这样的设置进行显示,所以如果我们想要某个组的控件图标显示为大图标或是小图标,就可以在这里进行设置。完成默认情况下的定义后,就开始定义控件的缩放策略了。在这里,按照次序,我们逐个定义在Ribbon面板尺寸变化时尺寸发生变化的组。当Ribbon面板的尺寸变化时,Ribbon界面中的控件将按照这样的次序发生重排,减少控件使用的面积,以使得Ribbon面板能够显示所有控件。

  Tab页面的缩放策略定义完成后,我们就可以开始定义控件的包含关系。这里,我们使用了组控件的SizeDefinition属性来定义组内控件的排布方式。例如,如果我们使用“TwoButtons”,表示组内有两个按钮,可以并排排布。如果我们使用“BigButtonsAndSmallButtonsOrInputs”,则表示组内有一个大的按钮,而其他的控件则是小按钮或者其他输入控件。下面这幅图演示了缩放策略所控制的Ribbon界面控件的缩放次序。当我们缩小窗口,Ribbon面板的尺寸减小,根据缩放策略中所定义的,首先缩小的是GroupDatabase组中的控件,以减小Ribbon面板中控件占用的尺寸。当窗口继续缩小,接着缩小的是GroupClipboard组中的控件,依次变为Medium模式和Popup模式。最后,当尺寸继续缩小,最重要的GroupMain组才开始改变尺寸。通过有次序的控制,我们可以先缩小不太常用的命令控件,而把最重要最常用的命令控件尽量保留在Ribbon界面上。通过这样的方式,可以让用户始终可以很快地找到最常用的命令控件。
 

  到此为止,我们基本上可以利用XML对Ribbon界面的各个元素进行定义了,同时能够控制Ribbon界面在各种尺寸下的显示状态,可以说跟界面相关的工作已经基本完成了。接下来的任务就是对控件的消息进行响应,以完成相应的业务逻辑。这回我们就说到这里,要知后事如何,且听下回分解。

1
相关文章