【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.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,然后在其中的命令部分添加下面的语句,定义相应的按钮控件:
<!--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)部分编辑代码,实现各个控件的排布:
<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属性来定义容器所使用的布局模板,例如:
这行代码就表示使用“'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)添加相应的控件描述:
<!--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文件的视图部分对控件进行布置并设置缩放策略:
<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界面在各种尺寸下的显示状态,可以说跟界面相关的工作已经基本完成了。接下来的任务就是对控件的消息进行响应,以完成相应的业务逻辑。这回我们就说到这里,要知后事如何,且听下回分解。