写点什么

论道 WP(三):应用程序栏

2012 年 5 月 24 日

5 月初我应邀参加了 QClub 大连站的活动,当时我给现场的观众分享了应用程序栏的使用心得,为了让更多朋友了解其中的内容,也让现场的观众将来可以回头参考,我根据演讲内容写成了这篇文章。

软键盘带来的问题

如果一个页面放置了文本框,那么当用户单击文本框时,软键盘将会显示,如图 1 所示。你是否想过这个软键盘的出现会带来什么问题呢?

图 1

细心观察一下图 1(右),不难发现两个文本框和一个按钮占据了屏幕的上半部分,而软键盘则占据了下半部分,刚好用完整个屏幕。如果页面不止两个文本框,而是四个,两个必填,两个选填,如图 2(左)所示(必填项将会放在上面,选填项则会放在下面,因为用户的阅读方向一般都是从上往下的),那么,当用户完成必填项的输入并希望立即保存时,就会发现按钮处于不可见状态,如图 2(右)所示。

图 2

此时,用户需要单击页面空白处关闭软键盘,才能看到并单击页面上的按钮,这里无疑多了一个不必要的步骤。别小看这个不起眼的步骤,如果用户需要连续录入十笔数据,那么每笔数据都要额外执行这个不必要的步骤显然会为用户体现带来负面影响。为了使得用户随时可以接触到按钮,我们可以把它们放在应用程序栏上,如图 3 所示,这样,无论用户正在输入那个文本框,按钮都在触手可及的地方。

图 3

然而,这种做法会带来一个小问题,这个问题会出现在使用 MVVM 模式的应用里。当用户在文本框处于编辑状态时单击应用程序栏上的按钮,文本框的修改不会更新到与之绑定的视图模型的属性,因为 Silverlight for Windows Phone 的文本框默认只在它失去焦点的时候才会执行更新,而单击应用程序栏上的按钮不会使文本框失去焦点。

解决方案是在文本框上使用 Coding4Fun Toolkit for Windows Phone 的 TextBinding.UpdateSourceOnChange 附加属性,它会使文本框在每输入 / 删除一个字符时都会执行更新,类似于 WPF 在绑定表达式里把 UpdateSourceTrigger 的值设为 PropertyChanged。

了解应用程序栏

应用程序栏由按钮和菜单项两部分组成,如图 4 所示。按钮的数目最多只能有四个,而菜单项的数目没有限制,但从图 4 可以看出,当菜单项的数目超过七个时,只能完整显示前面五个,第六个会被部分遮住,第七个之后需要用户向下滑动才能看到,因此我们最好把菜单项的数目控制在六个以内,从而避免额外的滑动操作。

图 4

那么,什么样的操作应该放在应用程序栏上呢?设想我们有一个页面显示一组数据,并提供了常见的添加、编辑和删除三个操作,那么这些操作是否都放在应用程序栏上呢?你可以这样做,但这不是最优的做法。

一般情况下,我们可以把这些操作放在应用程序栏上或者上下文菜单里,如图 5 所示,无论哪种做法都涉及了两个步骤,选中列表项然后单击应用程序栏上的按钮,如图 5(左),或者长按列表项然后单击上下文菜单里的菜单项,如图 5(右),区别在于两个步骤之间手指挪动的位移。

当目标操作位于上下文菜单里时,由于上下文菜单紧贴着目标列表项,用户只需稍微挪动一下手指就可以了,如图 5(右)红色箭头所示,而当目标操作谓语应用程序栏上时,用户的手指平均需要横跨半个屏幕,如图 5(左)黄色箭头所示,根据费茨法则,把目标操作放在上下文菜单里的做法较优。

图 5

当然,添加按钮应该保留在应用程序栏上,因为它和具体的列表项没有关系。看到这里,你可能已经总结出规律了,和具体的个体有关的操作应该放在上下文菜单里,否则应该放在应用程序栏上。

那么,应用程序栏上的按钮和菜单项又该如何看待呢?按钮默认是显示出来的,而菜单项则需要用户进一步展开才能使用,这种直接/ 间接的特点意味着我们需要在设计的时候有意识地把操作划分为常用和不太常用两组,前者以按钮的形式出现,而后者则以菜单项的形式出现。

按钮和菜单项可以存在多种状态,这里的状态包括启用和禁用两种状态,如图6 的add 按钮和clear 菜单项,也包括启用状态下的不同模式,如图6 的lock/unlock 按钮,这种做法类似于ToggleButton。

图 6

值得提醒的是,虽然我们可以使一个按钮拥有超过三个不同模式,比如说,单曲循环、顺序播放、列表循环和随机播放等,但这种做法可能会为用户带来困惑,应该尽量避免。更好的做法是对这些模式重新分类,比如把单曲循环和列表循环归为循环模式,顺序播放和随机播放归为播放模式。

毫无疑问,使用应用程序栏需要占用一些屏幕空间,我们可以通过一些技巧减轻这种影响,比如说,调整应用程序栏的透明度,或者把它最小化,如图7 所示,当用户展开最小化的应用程序栏时,按钮和菜单项都会显示出来。

图 7

如何绑定应用程序栏的属性?

或许每个MVVM 模式的实践者一开始都会期望应用程序栏上的按钮和Silverlight 的Button 控件一样,有一个Command 属性可以实现命令绑定,不幸的是,没有这种东西,更糟糕的是,应用程序栏以及相关的组件根本无法实现任何属性的绑定,因为它们不是依赖对象,它们甚至不是Silverlight 的一部分!

这个时候,我们需要借助一些第三方的库,比如 AppBarUtils ,它提供的 AppBarItemCommand 可以实现按钮或菜单项的 Text、IconUri 和 Command 三个基本属性的绑定,如代码 1 所示。

代码 1

AppBarItemCommand 是一个 Expression Blend 行为(Behavior),这意味着你可以在 Expression Blend 里通过简单的拖放和属性的设置实现上面三个基本属性的绑定,如图 8 所示。

图 8

此外,AppBarUtils 还提供了 AppBarItemNavigation 和 AppBarPropertyBinder 两个行为,前者用于实现单击按钮或菜单项打开一个页面的操作,而后者则用于实现应用程序栏众多属性的绑定,比如 IsVisible、IsMenuEnabled、Mode、Opacity、ForegroundColor 和 BackgroundColor 等属性。

使用内置 Expression Blend 行为

Expression Blend 行为是一个非常神奇的东西,它可以让你在 Expression Blend 里通过可视化的操作实现原本需要写代码才能实现的效果,比如说,你可以在 Expression Blend 里创建一个动画(Storyboard),然后通过 ControlStoryboardAction 控制这段动画的播放,又比如说,你可以通过 PlaySoundAction 播放一段音乐。现在的问题是,我们能否把这些行为用到应用程序栏上呢?

要回答这个问题,我们先要了解一下 Expression Blend 行为。拿 AppBarItemCommand 来举例吧,它包含了两个部分:

  • 能够触发这个行为的对象只有应用程序栏上的按钮或菜单项
  • 这个行为的效果是执行与之关联的命令对象

现在它们是封装到一块的,如果把它们分离开来,那么我们就能替换其中的触发条件或行为效果了。为此,Expression Blend 引入了触发器和操作两个概念,分别对应前面提到的两个部分,它们和行为的关系如图 9 所示。

图 9

ControlStoryboardAction 和 PlaySoundAction 等都是可重用的操作,要在应用程序栏上使用它们,我们需要一个针对应用程序栏的触发器,而 AppBarUtils 恰好提供了这样的东西——AppBarItemTrigger,有了它,你就可以把内置 Expression Blend 行为物尽其用了。

关于 AppBarUtils 的详细用法,你可以参考 Allen Lee 的《AppBarUtils 使用指南》以及这个工具包附带的示例代码。


感谢崔康对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012 年 5 月 24 日 00:001471

评论

发布
暂无评论
发现更多内容

架构师训练营第 1 期 week7

张建亮

极客大学架构师训练营

架构师训练营week07作业

FG佳

极客大学架构师训练营 week07

第七周作业(作业一)

Geek_83908e

极客大学架构师训练营

架构是训练营-第三周总结

工厂方法模式

猴子胖胖

golang 设计模式

架构师训练营 2 期 - 第 3 周命题作业

Geek_no_one

极客大学架构师训练营

「架构师训练营第 1 期」第七周作业

张国荣

三周学习总结

水浴清风

架构师训练营第二期 Week 3 作业

bigxiang

极客大学架构师训练营

架构师训练营第三周总结

张浩

架构师训练营第三周作业-手写单例模式

张浩

架构师训练营第七周作业

郎哲158

极客大学架构师训练营

架构师训练营 - 第 7 周课后作业 -性能压测

树森

架构师训练营 Week03 作业-手写单例模式

Calvin

训练营第七周作业2

仲夏

极客时间 - 架构师一期 - 第七周作业

_

极客大学架构师训练营 第七周作业

Architecture Phase1 Week7:HomeWork

phylony-lu

极客大学架构师训练营

架构师训练营—第七周学习总结

orchid9

第七周总结

睁眼看世界

极客大学架构师训练营

第七周架构师训练学习笔记

郎哲158

极客大学架构师训练营

一期二班-吴水金-第五课总结

吴水金

第三周作业

皮蛋

架构师

架构师 01 期,第七周课后作业

子文

架构师训练营week07总结

FG佳

训练营第七周作业 1

仲夏

极客大学架构师训练营

架构师训练营-单例模式

手写单例

落朽

性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

知行合一

架构师训练营 2 期 - 第三周总结

Geek_no_one

极客大学架构师训练营

第七周命题作业

orchid9

第七周作业

极客大学架构师训练营

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

论道WP(三):应用程序栏-InfoQ