WP7有约(三):课堂重点
俗话说好记性不如烂笔头。当然这并不是说我们的脑子不好使也不是叫我们不要用脑子记东西而是提醒我们解放脑力让大脑从事更有价值的思考。因此这节课我们将会创建一个笔记本用来记录课堂重点但是我们需要什么样的笔记本呢我曾经在《你的灯亮着吗》里读到这样一句话如果某人能够解决这个问题但是他本人却不会遇到这一问题时那么你们首先要做的就是让他也感受到这个问题。最近公司来了一批校招生我找了个机会混进去听了一节入职前的技术培训我想知道在课堂上把手机掏出来记笔记是一种什么样的感觉。在课堂上每当我想记点什么时就会不自觉地拿起纸笔而不是手机而且用手机记笔记远没用纸笔来得随意自如。随后我找了一些大学生和中学生分别了解一下他们记笔记的情况结果发现他们记笔记的方式真是多种多样有的直接记在书上有的记在专门的笔记本上有的记在练习册上有的记在卷子上有的甚至用手机把老师的板书直接拍下来……不难看出他们的做法是怎么方便就怎么记就目前而言企图用一个手机应用来取代他们现有的做法显然是不现实的也没必要用户有权选择他们认为适合的做法而我们的职责只是提供必要的帮助和支持。那么我们可以提供什么样的帮助和支持呢想想看现有的自由零散的做法会导致什么问题呢最直接的影响是很难快速找到想要的内容因为它们可能遍布各处这种时候要是有个索引或者目录什么的就好了……Bingo我们可以创建一个应用帮助用户建立这个索引虽然用户也可以另外找本小册子建立索引但我们可以通过一个标签系统帮助用户快速找到相关的内容。这样用户既可以保留现有的自由的记笔记习惯又可以获得新的有序的管理效果。那么用户应该在何时以及如何建立这个索引呢当然是越早越好比如说用户可以在每晚做完作业之后稍稍整理一下笔记然后为它们创建一些条目并贴上标签。用户不必为所有笔记创建条目可以挑选重要的来创建这个过程本身就可以加深对知识的理解和巩固对知识的记忆。至于条目的内容用户可以引用课本或者老师板书的原话也可以用自己的话来概括复述还可以直接引用课本或者练习册的页码和位置段落、题号或者标记等等这个过程可以帮助用户熟悉如何根据条目的内容找到对应的笔记。现在用Visual Studio打开项目在Models文件夹里创建一个Note类并让它继承NotificationObject类代码 1根据前面的讨论Note类应该包含以下四个属性属性名字属性类型属性描述IdGuid唯一标识Coursestring课程名称Contentstring笔记内容Tagsstring笔记标签表 1其中Id是只读属性根据上节课的经验我们需要给它创建以下两个构造函数代码 2它们分别用于新建和编辑两种情景。Course、Content和Tags三个属性的set访问器均需调用RaisePropertyChanged方法此方法是从NotificationObject类继承过来的。Tags属性可以包含一个或多个标签当Tags属性包含多个标签时标签与标签之间将会使用逗号,进行分隔。数据存储方面我们将会直接使用上节课重构的结果——JsonDataStore类。打开App.xaml.cs文件在App类里创建一个NoteStore静态属性代码 3接下来是时候考虑一下用户体验了。设计用户体验我们知道每门课都有自己的笔记就像每门课都有自己的作业一样所以这里将会仿效作业本的做法利用Pivot控件的特点让每个Pivot项显示一门课程的笔记。现在切换到Expression Blend创建一个Windows Phone Pivot Page并把它命名为NoteBookPage.xaml完了之后把Pivot控件的Title属性设为笔记本把两个Pivot项的Header属性分别设为销售心理学和行为金融学图 1需要说明的是Application Bar上的按钮没有设置图标这是因为我没有找到合适的下次有时间我自己设计一个放上去。那么标题下面这么大的一块空位应该怎么安排呢首先有两点我们是明确的第一我们需要列出笔记第二我们需要提供某种方式让用户切换标签。根据以往的经验ListBox最适合用来列出笔记至于切换标签的方式我觉得SL for WP Toolkit的ListPicker也是一个不错的选择。此时我的脑子里浮现出第一个设计图 2然而很遗憾我对这个设计并未感到满意。第一在手机屏幕这样的有限空间里我们应该始终坚持把尽可能多的空间留给最重要的内容ListPicker作为一个辅助元素应该只在用户需要切换标签的时候才显示否则把空间腾出来这样可以显示更多笔记。第二笔记本和作业本、课程表有着类似的布局设计但ListPicker的存在破坏了布局设计的一致性这点我实在无法容忍。那么怎样才能让ListPicker呼之则来挥之则去我们可以调整ListBox的大小使之充满整个Pivot项并把ListPicker藏在屏幕下方外面然后在Application Bar上放置一个按钮当用户单击这个按钮时ListPicker将会从屏幕下方外面向上平移直至屏幕底部图 3这样用户就可以通过ListPicker切换标签了。此时我的脑子里冒出一个问题为什么不直接以这种方式显示标签列表而是大费周章地通过ListPicker打开一个新的页面呢显然我找不到合适的理由说服自己把ListPicker留下同时这个问题也给我带来了新的灵感。我们可以让显示标签的ListBox取代ListPicker当用户单击Application Bar上的按钮时ListBox将会从屏幕下方外面向上平移直至覆盖显示笔记的ListBox为止当用户选好标签之后显示标签的ListBox将会向下平移直至屏幕下方外面为止。现在把ListPicker删除然后把一个ListBox添加到LayoutRoot并调整它的大小使之充满整个屏幕覆盖后面的Pivot控件。此时Objects and Timeline面板上面的对象应该是这样的图 4接着把它向下平移直至它的顶部和Pivot控件的底部重叠为止图 5此时它的Height、VerticalAlignment和Margin三个属性都会自动做出相应的调整图 6接下来我们将会为它创建动画。单击Objects and Timeline面板上的按钮图 7在弹出的Create Storyboard Resource对话框里输入一个名称然后按OK关闭对话框图 8此时Objects and Timeline面板将会变成这样图 9确保ListBox处于选中状态把播放指针拖到0.5秒的为止然后把ListBox向上平移直至和Pivot控件完全重叠为止。此时Objects and Timeline面板将会变成这样图 10看到这里你可能会问为什么只有结束时间的关键帧你也可以手动设置开始时间的关键帧如果没有设置那么对象原本的状态将会默认为开始时间的关键帧。当用户选好标签之后我们需要把ListBox隐藏起来不难想象隐藏动画其实是显示动画的反转那么如何创建反转动画呢非常简单单击按钮旁边的箭头然后选择Duplicate图 11此时Expression Blend会为你创建一个ShowTagsStoryboard_Copy1动画。单击按钮旁边的箭头然后选择Rename把它重命名为HideTagsStoryboard。接着再次单击按钮旁边的箭头然后选择Reverse反转动画。好了之后单击按钮旁边的X按钮关闭Storyboard。那么我们如何触发这些动画前面说过当用户单击Application Bar上的按钮时ListBox将会显示这个比较简单只需在按钮的事件处理程序里调用ShowTagsStoryboard的Begin方法就可以了代码 4而当用户选好标签之后ListBox将会隐藏这个可以通过Expression Blend提供的ControlStoryboardAction来实现。打开Assets面板选择Behaviors然后把ControlStoryboardAction拖到Objects and Timeline面板的ListBox上图 12此时Objects and Timeline面板将会变成这样图 13确保ControlStoryboardAction处于选中状态在Properties面板上把EventName和Storyboard两个属性的值分别改为MouseLeftButtonUp和HideTagsStoryboard图 14这样当用户在ListBox里选好标签并松开手时就会触发HideTagsStoryboard。看到这里你可能会问为什么前面不直接在Application Bar的按钮上使用ControlStoryboardAction这是因为Application Bar并非Silverlight的一部分你不可以把它和我们平时接触到的Silverlight对象等同起来。事实上如果你试图把ControlStoryboardAction拖到ApplicationBarIconButton上Expression Blend会提示你Not a valid drop target图 15接下来我们将会为两个ListBox定制数据模板。首先通过Data面板导入以下两个XML文件代码 5