Written by Allen Lee
添加配置文件
首先,向项目添加一个Options.xml文件,这个文件将会用来储存应用程序的配置信息:
图 1
接着,把Options.xml的Copy to Output Directory属性的值改为Copy if newer:
图 2
然后,就是为Options.xml添加配置信息了:
代码 1
那么,我们如何使用这个文件呢?关于这个问题,我首先想到的是为它创建一个OptionManager类,在我的想象里,它应该是这样使用的:
代码 2
在继续之前,我想请你思考一个问题:你会如何实现OptionManager的Options成员呢?下面是我的做法,使用了单例模式和索引器:
代码 3
当然,你也可以学ConfigurationManager类那样,通过AppSettings静态属性返回一个NameValueCollection对象。接下来的问题是,如何访问Options.xml呢?由于Options.xml上面的配置信息实际上只是一组键/值对,于是你可以考虑在OptionManager的构造函数里把它们全部读到一个内部的Dictionary对象里:
代码 4
LoadOptions方法使用了LINQ to XML来读取Options.xml里的配置信息,并以Dictionary的形式返回:
代码 5
这里使用了GetXmlPath方法来获取Options.xml的路径:
代码 6
OptionManager提供了一个Save方法,用于保存配置信息:
代码 7
其中,SaveOptions方法也使用了LINQ to XML来构建并保存配置信息:
代码 8
最后就是OptionManager的索引器了:
代码 9
设计选项窗体
说到选项窗体,你会如何设计?我想象中的选项窗体大致像这样:
图 3
我用了一个NumericUpDown控件来收集MaxSelectionCount的配置信息,另外用了两个DateTimePicker控件分别收集MinDate和MaxDate的配置信息。
接着,我们来看看底下两个菜单项。Cancel菜单项比较简单,仅仅把窗体的DialogResult设为Cancel:
代码 10
而OK菜单项的任务就多一点,它要保存用户的配置信息:
代码 11
接着就是修改一下主窗体的菜单:
图 4
Save菜单项和以前一样,而Options菜单项将会打开选项窗体:
代码 12
现在,我们来运行一下这个应用程序:
图 5
图 6
有问题!选项窗体打开的时候,上面的控件没有反映配置文件里面的信息,这是因为我没有实现这样的逻辑,同样地,这个问题也会发生在主窗体身上,这意味着无论我们如何修改配置文件,重新启动应用程序之后,主窗体将会恢复默认配置,何等严重!
首先是选项窗体打开的时候需要读取配置信息到对应的控件上:
代码 13
代码 14
由于读取配置信息的代码和代码12里的那部分是相同的,所以我把它提取出来,放在SetupOptions方法里,这样,代码12就简化为:
代码 15
再次运行应用程序:
图 7
这次正常了。不过还有一个小问题,选项窗体里保存配置信息的代码属于OK菜单项而不是选项窗体的,当用户单击窗体右上角的OK按钮时,虽然窗体的DialogResult属性返回OK,但实质上没有执行任何保存配置信息的操作,这就导致了窗体行为的不一致。解决这个问题的办法有两个,一个是去掉窗体右上角的OK按钮,另一个是把OK菜单项里保存配置信息的代码放到窗体层面上做。前一种做法很简单,只需要把选项窗体的ControlBox属性设为false就行了。至于后一种做法,在继续讨论之前,我想先考一考你,我应该选择Deactivate事件还是Closing事件呢?答案是两个都可以,因为选项窗体是通过ShowDialog方法打开的,关闭这样的窗体是真的关闭了而不是像主窗体那样最小化到后台,所以我们可以放胆使用Closing事件:
代码 16
还有一个不是问题的问题,就是当你关闭选项窗体时,你会发现画面突然停顿,你知道这个时候OptionManager在保存配置信息,但用户并不知道,这可能会给用户留下不好的印象/感受,要让用户知道后台正在执行任务,最简单的办法就是在屏幕正中显示等待指针,当然,任务完成之后记得去掉等待指针,否则……
你还想要什么?
下一集,除了上一集剩下的两个需求之外,我们还会探讨两个新的需求:
- 支持日期的包含,比如说2009年2月14日被指定为届时要选的日期。
- 如果指定一个周期,应用程序将会综合排除逻辑、包含逻辑和这个周期计算下一个将要被选中的日期,并显示在主界面上。
相关文章:WM有约(一):你好,CF