WM有约(四):处理屏幕旋转

WM有约(四):处理屏幕旋转

 

Written by Allen Lee

 

如果用户旋转屏幕……

首先,运行一下应用程序:

图 1

接着,旋转一下屏幕:

图 2

噢,"下一次"被挤下去了,屏幕也出现了滚动条,然而,屏幕上仍有许多空白地方未被利用,怎么办?

 

支持屏幕旋转的控件

以前,patterns & pactices提供了一个Mobile Client Software Factory,里面有一个OrientationAware控件,可以帮我们应对这种情况。现在,Clarius Consulting提供了一个专门用来应对这个问题的Orientation Aware Control组件,下面我们将会探讨如何使用Community Edition来解决这个问题。

安装好Orientation Aware Control组件之后,Add New Item对话框里会有一个Orientation Aware Control:

图 3

选中这个项,给它一个名字,然后单击Add,你会得到一个空白的控件设计界面,把HomeForm上的MonthCalendar控件和两个Label控件复制到HomeControl上,调整它们的位置,使它们居中:

图 4

接着,右键单击控件的空白处,选择Rotate:

图 5

控件的设计界面将会旋转:

图 6

这幅图运行后的样子实际上就是图2,现在把控件上的东西重新调整一下:

图 7

需要说明的是,我把控件的Size设为和HomeForm的一样,竖着的和横着的分别对应起来。然后,把控件旋转回去,把它添加到HomeForm上,并把它的Dock属性设为Fill:

图 8

哎哟,有点不堪入目啊,不知道运行起来会不会也是这样呢?好,我们来看看:

图 9

图 10

嗯,处理得还算不错,虽然横屏时还是出现了滚动条。注意,由于目前HomeControl只是一个空壳,所以之前实现的所有功能都不会在上面产生作用,当然就包括"下一次"没有任何显示了。

 

把业务逻辑的代码分离出来

目前,用户界面的代码和业务逻辑的代码纠缠在一起,HomeForm.cs里的代码更是超过四百行,这无疑会为将来的维护带来问题(虽然我不打算维护这个示范程序,但门面话还是要说一下的,哈哈),于是,接下来将会尝试把用户界面的代码分离到HomeControl里,而业务逻辑的代码将会创建一个新的DateManager类来存放。

DateManager类将会负责日期的存取、文件管理和预测逻辑;而HomeControl将会负责MonthCalendar上钉住日期的更新、"下一次"的更新和获取用户选中的日期。

首先是文件管理,HomeForm.cs里的InitializeFile、GetPinnedDatesFilePath、GetExcludedDatesFilePath、GetIncludedDatesFilePath和GetFilePath等方法可以直接复制到DateManager类里,其中InitializeFile将会在DateManager类的构造函数里调用,以便创建用来储存日期的文件。

接着是日期的存取,HomeForm.cs里的LoadDates、SaveDates、LoadPinnedDates、SavePinnedDates、LoadIncludedDates、SaveIncludedDates、LoadExcludedDates和SaveExcludedDates等方法都可以直接复制到DateManager类里,然而,由于DateManager类是用户界面中立的,于是需要对外提供Load和Save两个方法,以便相关的窗体/控件调用:

代码 1

最后就是"下一次"的预测了,HomeForm.cs里的CalculateNextTime、CalculateNextSaturday、ApplyInclusion、ApplyExclusion和ApplyAdjustment等方法都可以直接复制到DateManager类里,另外,我们需要把CalculateNextTime方法变成公有方法,以便HomeControl调用。

慢着!我怎么添加日期?噢,差点忘记了~~~我们知道,DateManager并不需要关心你是否在添加一个周末,它的任务只是把你给它的一组日期添加到对应的集合,于是我们可以这样实现Pin、Include和Exclude三个方法:

代码 2

再等等!我怎么获取要显示在MonthCalendar上的钉住日期?很简单,只需要提供一个PinnedDates属性就可以了:

代码 3

 

把用户界面的代码分离出来

我们知道,HomeControl的职责是显示钉住日期、更新"下一次"和在用户选中日期时发出通知,对于前两个,我们只需简单地提供两个属性就可以了:

代码 4

对于后面那个职责,我们需要提供一个SelectedDatesChanged事件,它会在MonthCalendar控件的DateChanged事件的基础上加上是否为周末的判断逻辑。为了实现这个事件,我们需要创建一个SelectedDatesEventArgs类:

代码 5

其中,CalculateWeekend和CalculateRange两个方法是从HomeForm.cs里直接复制过来的。有了这些准备,我们就可以着手实现SelectedDatesChanged事件了:

代码 6

还差什么呢?对了,是配置信息的设置,把HomeForm.cs里的SetupOptions方法直接复制过来,并把它变成公有方法。

最后就是着手整理HomeForm.cs了。首先,应用程序启动的时候,我们需要设置HomeControl的配置信息,并调用DateManager的Load方法:

代码 7

当主窗体的Deactivate事件触发时和用户单击Save菜单项时,调用DateManager的Save方法:

代码 8

当主窗体的Activated事件触发时,更新HomeControl上的"下一次":

代码 9

当用户通过OptionForm修改了配置信息时,调用HomeControl的SetupOptions方法读取配置信息:

代码 10

当用户在HomeControl里的MonthCalendar上做出选择,我们将会把用户选中的日期保存到一个私有变量里,然后根据SelectedDatesEventArgs的ArePast属性设置Pin、Include和Exclude三个菜单项的Enable属性:

代码 11

当用户单击Pin、Include和Exclude三个菜单项时,将会调用DateManager对应的方法来处理:

代码 12

最后,HomeForm.cs里的其他代码,包括辅助方法和原用户界面上的控件都要删除。

现在,是时候运行一下应用程序了,看看改了这么多有没有改坏了:

图 11

噢,钉住日期没有显示出来!没问题,只需要在主窗体的Activated事件触发时和用户单击Pin菜单项时把DateManager的PinnedDates属性的值赋给HomeControl的DataSource属性就可以了。再次运行应用程序,这次就正常了(奇怪,为什么图10上会多出一个滚动条呢?难道是因为之前没有把窗体上原有的控件删除?):

图 12

图 13

 

你还想要什么?

原本还想试一下数据绑定的,不过现在看来也没有这个必要了。目前这个应用程序基本上可以投入应用了,所以下一步就是如何把它部署到设备上。下一集,我们将会探讨如何为这个应用程序开发安装包。

posted @ 2008-12-21 21:18 Allen Lee 阅读(3034) 评论(21) 编辑 收藏

 回复 引用 查看   
#1楼 2008-12-21 21:22 李永京      
沙发,写的不容易~~~小A辛苦啦
 回复 引用 查看   
#2楼 2008-12-21 21:38 王孟军!      
请问楼主 是不是所有的WM的控件都可以 旋转 有没有 性能影响 需不需要 为选择 而CODE额外的编码? 谢谢
 回复 引用 查看   
#3楼 2008-12-21 21:55 micYng      
理论上都可以旋转,这是WM自带的功能而已,跟具体控件无关
据我所知,需要额外编码处理坐标...

 回复 引用   
#4楼 2008-12-21 22:30 Ariex[未注册用户]
看来很多人都喜欢这个颜色作为IDE的背景么~
 回复 引用 查看   
#5楼 2008-12-21 22:50 Anders Cui      
支持一下:)
 回复 引用 查看   
#6楼[楼主] 2008-12-22 08:27 Allen Lee      
@李永京
@Anders Cui
谢谢!

 回复 引用 查看   
#7楼[楼主] 2008-12-22 08:35 Allen Lee      
@王孟军!
@micYng
旋转屏幕是WM自身的功能,一般情况下,如果我们用户界面的布局是为横屏设计的,那么当我们的应用程序运行在竖屏上布局就可能产生不适应症状,反过来为竖屏设计的布局在遇到横屏的设备也可能会乱了套,更不用说用户可以自行旋转屏幕了。Orientation Aware Control的作用就是不用写额外的代码,帮你应付因为屏幕旋转而导致的布局混乱,你只需要在控件上设计对应不同屏幕方向的布局就行了,它会自动获取WM屏幕旋转的消息,然后按照你的不同屏幕方向的设计调整布局。如果没有这样的控件,要我额外写代码手动计算坐标,我宁愿分别为两个屏幕方向写两个程序,呵呵~~~

 回复 引用 查看   
#8楼[楼主] 2008-12-22 08:36 Allen Lee      
@Ariex
这个嘛~~~没有做过统计~~~很多人用么?

 回复 引用 查看   
#9楼 2008-12-22 09:07 AlphaWu      
支持一下!!
需要这样的好文章
 回复 引用 查看   
#11楼 2008-12-22 11:09 毁于随      
以前试过,不过是自己调API试的.
 回复 引用 查看   
#12楼 2008-12-22 11:49 U2U      
你这个系列的文章写得很棒!加油!
 回复 引用 查看   
#13楼[楼主] 2008-12-22 12:45 Allen Lee      
@AlphaWu
@商业机密审查小组
@U2U
谢谢你们的支持!

 回复 引用 查看   
#14楼[楼主] 2008-12-22 12:45 Allen Lee      
@毁于随
你也可以把你手动调用API的经验分享出来呀。

 回复 引用 查看   
#15楼 2008-12-22 13:56 施炯      
支持这个讲WM UI系列的文章
 回复 引用 查看   
#16楼 2008-12-22 15:49 JustDI      
收下了,不过提个建议,代码用图片截的有点模糊,编辑器自带的code就很不错呀。
 回复 引用 查看   
#17楼[楼主] 2008-12-22 18:51 Allen Lee      
@施炯
谢谢!

 回复 引用 查看   
#18楼[楼主] 2008-12-22 18:52 Allen Lee      
@JustDI
这些文章使用Word 2007来写的,所以代码以图片的形式给出,为了节省空间,图片都缩小了...

 回复 引用 查看   
#19楼 2008-12-23 09:41 毁于随      
--引用--------------------------------------------------
Allen Lee: @毁于随
你也可以把你手动调用API的经验分享出来呀。
--------------------------------------------------------
好早以前的事了,早不知扔哪了.呵.反正我记得不是很难.

 回复 引用 查看   
#20楼 2008-12-25 12:04 fox23      
excellent article ;-)
 回复 引用 查看   
#21楼 2009-02-09 09:14 tatung zhang      
不错 顶个...