随笔-195  评论-1124  文章-1  trackbacks-4

《101 Windows Phone 7 Apps》读书笔记-BABY NAME ELIMINATOR

课程内容

Ø本地数据库

Ø在应用程序中处理数据

 

    Baby Name Eliminator是一种通过输入性格特征而获取婴儿名字的应用程序(我和我的妻子用这种方法来为两个儿子取名字)。与采用头脑风暴的方式取名字、而后又担心错过了最好的名字不同,本应用程序使得我们利用淘汰法为婴儿取名。

    Baby Name Eliminator建立在一个巨大的数据库之上,它存放了美国范围内使用的36,065个男孩名字和60,438个女孩名字。在我们选定性别以后,应用程序会使用多种过滤器来缩小名字列表。这些过滤器建立在以下几个因素的基础之上:每个名字的受欢迎程度、名字的开头和结束字母以及该名字首次使用的时间。一旦对列表进行过滤之后,我们就可以一个个得对名字进行排除,直到做出最后的选择。

    在为孩子取名字时,我们会进行多次考虑,排除那些明显不好的,留下我们犹豫不决的。在我们静下心来对待20个可选择的名字时,我和妻子各自选择认为最好的5个。对于第一个儿子,我们选取了共同的名字,所以就这样下了最后的决定。如果你和妻子都有Windows Phone手机,那么各自选择名字、直到列出候选名单,这种方式将非常有趣。

    那么,这个名字数据库从何而来呢?答案是社会安全局,它可以提供1880年以来几乎每个社会安全卡上的姓名。这张表有几点需要说明:

➔ 出于隐私的原因,只包含给定年份中使用5次以上的名字。

➔ 单个字符的名字不包括在内。

➔ 1937年之前出生的许多人没有社会安全卡,所以那些年的数据不全。

➔ 相同名字的不同拼写被视为不同的名字。

➔ 数据未经加工,也未经排错。有时候申请表上的性别是错误的,导致女孩名字列表上出现男孩子的名字,同时相反的情况也存在。除此之外,一些名字被记录为“未知”,“未命名”,或者是“婴儿”。这些情况可以通过限制列表的前1000个名字来解决。

    为使能这种过滤,本应用程序利用了两个本地数据库-一个存放男孩名字,另一个存放女孩的名字。

 

Working with Local Databases

    Windows Phone 7缺少对本地数据库的支持是其公认的缺点之一。鼓励应用程序与服务器端的数据库配合工作,但是这对于开发者来说会引入额外的负担,对于用户来说会带来更多的麻烦(延时,数据连接,潜在的数据流量成本)。幸运的是,我们可以选择第三方数据库。我最喜欢的是开源的SQLite for Windows Phone 7,它由Dan Ciprian Ardelean所创建。我们可以在以下网页中进行查看:http://sviluppomobile.blogspot.com/2010/03/sqlite-for-wp-7-series-proof-of-concept.html并通过以下链接获取最新的版本:http://www.neologics.eu/Dan/WP7_Sqlite_20.09.2010.zip它包含了C#源代码和一个Community.CsharpSqlite.WP.dll文件,我们可以在工程中对它进行引用。它当然不可能没有缺陷,但是在多数情况下它都工作得非常好(比如本应用程序)。

    SQLite for Windows Phone 7从隔离存储空间中读取或者写入数据库文件。如果我们想要把填充好数据的数据库和应用程序一起部署,我们可以将数据库文件包含到工程中,并且把Build Action设置为Content。在运行时,第一次使用SQLite之前,我们的应用程序获取文件,并把它存储到隔离存储空间中。在工程中要以内容的方式访问文件,我们可以调用Application. GetResourceStream。

如何创建一个随应用程序部署的包含数据库的.bd文件?

   以下就是在Windows Phone应用程序中的方法:

1. 执行CREATE TABLE和INSERT命令,使用SQLite产生一个数据库。

2. 利用隔离存储空间的API,获取SQLite存储到隔离存储空间中的.db文件的原始数据。

3. 从Visual Studio debugger拷贝字符数据作为Base64编码的字符串,使用另外的(桌面)程序解码,将它们存储到需要的.db文件中。

注意:

➔ 在执行大量的数据库操作时,为了使得用户界面可响应,与SQLite的交互是通过BackgroundWorker的后台线程来完成的,通过回调函数来获取成功/失败信息。

➔ 传递给ExecuteScalar和ExecuteQuery的命令字符串可以是SQL命令,比如:SELECT COUNT(*) FROM table

➔ ExecuteQuery是一个通用的方法,其通用参数T必须是一个类,且具有一个与查询中选择的列相一致的属性。

    Application.GetResourceStream与工程中包含的文件配合工作,文件的Build Action设置为Content,或者Build Action设置为Resource。对于后者,传入的URI必须符合下面的语法:/dllName;component/pathAndFilename

    注意,dllName可以引用.xap文件中的任何dll,只要它包含需要的资源。但是,不能包含dll后缀。

    对于本应用,位于工程根目录的男孩名字数据库(Boys.db)的DatabaseName字符串如下所示,

    /WindowsPhoneApp;component/Boys.db

    但是,如果这样的话,列表24.1使用的SaveFile就必须更改,因为DatabaseName字符串对于隔离存储空间来说,不再是一个有效的文件名。

 

Application.GetResourceStream与Assembly.GetManifestResourceStream

    我们可能偶然发现Assembly.GetManifestResourceStream API是作为读取包含在应用中的文件的方法。这样是可行的,但是仅仅限于那些Build Action设置为 Embedded Resource的文件(而不是设置为Resource)。

    但是,传递给GetManifestResourceStream的字符串具有它独特的语法:dllName.filename中dllName是包含embedded resource的DLL的名字。那是因为在命名每个embedded resource 时,C#编译器自动将DLL名字(减去.dll扩展名)前置到文件名中(你可以通过诸如.NET Reflector工具来打开DLL查看名字)。本应用中,两个有效的字符串是“WindowsPhoneApp.Boys.db”和“WindowsPhoneApp.Girls.db”。

    相对于这种方法来说,Application.GetResourceStream更加灵活。与其他那些将文件作为嵌入式资源的机制相比,使用作为内容方式文件的GetResourceStream方法更加受人欢迎,因为资源会增加DLL文件的大小,并且那样会增加应用程序的加载时间。

 

The Filter Page

    我们可以通过浏览包含的源代码来查看应用程序的主页面,但我们首先要查看利用DatabaseHelper类的过滤页面。过滤页面如图24.1所示,显示了列表中有多少个名字,然后,我们能够利用一些选项来过滤它,这些选项可以映射为SQL查询命令,并作用在数据库上(男孩与女孩名字在之前的主页面上进行选择)。

image

图24.1

    如图24.2所示,每个按钮会揭示一个新的窗口或者页面,那使得用户可以控制每个相关的过滤条件。点击名字的数量会揭示真实名字的列表,如图24.3所示。该列表不能进行交互式的排除,但是,那可以在主页面中来完成。

image

图24.2

image

图24.3

注意:

➔ 点击按钮时弹出的对话框是由Dialog用户控件所创建的,这可以在应用程序的源代码中看到。字幕的网格由LetterGrid用户控件所创建。这里的网格与第18章“Cocktails”中的QuickJumpGrid控件很类似。

➔ 5个过滤按钮是toggle类型的,它们的IsChecked状态由背后的代码来管理。如果一条过滤条件被激活,它相关的按钮会被检查(高亮),使得用户可以在不用点击每个按钮的情况下看到它,也不用对其过滤条件进行双重检查。

➔ 在后台线程执行查询时,进度条和它相关的用户界面会显示出来,如图24.4所示。因为它不会占据整个屏幕,所以如果用户不在意等待当前名字的话,它允许用户继续工作。

➔本工程包含了两个数据库(Boys.db 和Girls.db),它们具有相同的模式。它们只包含一张名为Names表,该表具有三个列:Name,BestRank(它单个年份中最好的排名)和FirstYear(在社会安全数据库中首次出现的年份)。

➔ 刷新名字数量的查询命令为“SELECT COUNT(*) FROM Names”,它可以具有WHERE子句,它们建立在那些由过滤法则决定的设置之上。

➔ 显示真实名字的查询命令为“SELECT Name FROM Names”,它同样可以具有WHERE子句。因此,与ExecuteQuery 一同使用的Record类具有单字符串的Name属性。ToString方法允许Record集合可以作为没有任何数据模板的list box预览的数据源,因为text block中内置的ToString已经足够。

➔正如前一章中的date picker一样,本应用对每个字符选择都使用双向数据绑定。

posted on 2012-08-11 07:57 施炯 阅读(...) 评论(...) 编辑 收藏