65.9K
CodeProject 正在变化。 阅读更多。
Home

DayMon - 查看谁的生日即将到来

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2007 年 3 月 30 日

5分钟阅读

viewsIcon

45141

downloadIcon

708

小型的 Windows Vista 侧边栏小工具,可帮助那些希望被提醒即将到来的生日的人。

Screenshot - daymon.jpg

引言

让我们从我个人的经历说起。

很久以前,我写了一个纯粹供个人使用的小应用程序,它可以在我快要忘记某人生日时通知我。这是一个很好的方式,让你可以在朋友生日时想到他们。他们不需要知道是你的电脑在留意这件事。

当我第一次安装 Windows Vista 时,我注意到了侧边栏(是的,我知道,很难不注意到它),并且注意到很多东西都是基于 XML 的——最明显的是联系人。我看到了很多与之相关的工具(例如地址簿风格的),但没有什么可以提醒我即将到来的生日和/或纪念日。

这正是这个小工具将要做的事情。

下载次数

你会注意到这里有两个下载项。一个是整个东西的源代码,另一个只是小工具本身。

JavaScript

Windows Vista 侧边栏小工具有一些限制。对于 .NET 开发者来说,我最不喜欢的一点是它不支持使用 .NET 对象。听到微软公司一直宣传 .NET,但新的操作系统组件却只支持 COM,这很令人恼火。我需要一种方法来调用我自己的 .NET 代码。

有几种方法,最值得注意的是使用 .NET 互操作来支持 COM 使用,但问题在于你需要以某种方式注册它。这与小工具无需安装的特性不符。而且手动在注册表中输入注册信息也不是我喜欢的方式。

唯一可行的方法是利用读取标准输出并将其放置在某个标签中的可能性。

var shell = new ActiveXObject("WScript.Shell");
var exec = shell.Exec("file.exe /arg1 /arg2");
document.getElementById('Output').innerHTML = exec.StdOut.ReadAll();

这个选择的缺点是我必须在我的程序中使用一些 HTML 代码来实现这一点。

由于配置也使用 HTML/JavaScript 编程风格,这个决定的一个缺点是我们需要通过命令行参数将每个可配置参数传递下去。

C#

很明显,我需要创建一个控制台项目。然而,事实证明这是一个错误的选择,因为当你调用一个控制台应用程序时,控制台窗口总是会显示出来,这很恼人。正确的做法是构建一个普通的 Windows 应用程序。你仍然可以获得控制台输出,只是没有那个黑色的窗口。这正是我们所需要的。

解析命令行参数是必需的,我随意地重复使用了我的一门类来实现这个目的,所以唯一需要注意的是它确实有效。

一旦我们加载了所有东西,就可以开始解析了。它只是递归地进入每个子目录,并将每个文件放入一个数组中。我知道这会浪费少量内存,因为并非所有联系人文件都定义了日期,但这使得调试更容易,也更易于遵循。

接下来检索生日和纪念日。它们都通过一个小状态机进行处理,该状态机通过 XmlTextReader 解析 XML。数据被创建为一个类,并在类中计算下一个生日日期。

try {
    thisYearDate = new System.DateTime(System.DateTime.Today.Year, 
                       this._date.Month, this._date.Day);
} catch (System.ArgumentOutOfRangeException) {
    thisYearDate = new System.DateTime(System.DateTime.Today.Year, 
                       this._date.Month, this._date.Day - 1);
}
if (thisYearDate >= System.DateTime.Today) {
    this._nextDate = thisYearDate;
} else {
    try {
        this._nextDate = new System.DateTime(System.DateTime.Today.Year + 1,
                                    this._date.Month, this._date.Day);
    } catch (System.ArgumentOutOfRangeException) {
        this._nextDate = new System.DateTime(System.DateTime.Today.Year + 1,
                                    this._date.Month, this._date.Day - 1);
    }
}

对于那些出生在 2 月 28 日的人,需要进行一些异常处理。

该数组的所有元素都按该日期排序。

int IComparable<OneDay>.CompareTo(OneDay other) {
    return System.DateTime.Compare(this.NextDate, other.NextDate);
}

拥有泛型是件好事。

之后要做的就是以 HTML 格式输出前几个日期(记住我们直接填充的是“Output”标签)。这就是 HTML 标签的所有内容。你会注意到的唯一区别是它会写入 XmlTagWriter,它提供了一种更简单的方式来填充 XML 数据。由于它内部使用了众所周知的 XmlTextWriter,我认为不会有任何问题。

小工具

一切完成后,必须进行打包。由于我将所有文件都用作内容,Visual Studio 被“迫使”将所有文件输出到同一个目录。只需删除 .pdb 文件,然后压缩所有其他文件。压缩文件必须重命名为 .gadget 扩展名,这样就可以了。

可能的改进

内存使用情况

内存使用可以得到改进,方法是不要一次性加载所有生日然后稍后再排序。只需创建一个小列表,并将每个日期与该列表的阈值进行比较(通过列表中的所有先前日期计算)。为什么我没有这样做?嗯,这样更容易调试——你确切地看到了即将到来的生日的顺序,而且对我来说,我联系人中输入的生日数量是有限的。这样一来,内存消耗应该也很低。

不调用 exe

XML 文件的解析可以从 JavaScript 本身完成。这样,就可以避免调用单独的可执行文件。我为什么不这样做?这会让我付出更多的努力,而对最终用户来说变化不大。此外,这样我就可以获得现代编程语言过程的所有好处,而且没有什么是我做不到的。

更快的更新

有一个 FileWatcher 来在检测到更改时更新生日列表会很好。但这种基于超时的刷新是可以接受的。一旦输入了所有生日,它们本质上是静态的。没有必要让我们的系统负担实时监视。

历史

2007-04-06

  • 修复了日期解析错误
  • 重新打包源文件,以删除只读属性
© . All rights reserved.