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

ForestPad - 一种存储和检索文本信息的方法

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.85/5 (13投票s)

2004年6月1日

CPOL

11分钟阅读

viewsIcon

133662

downloadIcon

448

三个应用程序:PocketPC、Windows桌面和Web服务协作,以同步您的文本信息。

ForestPad - a method for storing and retrieving textual information

引言

ForestPad是一种存储和检索文本信息的方法,它由三个应用程序组成。

  • 一个PocketPC应用程序 (截图)
  • 一个Windows桌面应用程序 (截图)
  • 一个Web服务应用程序

还包含两个安装程序项目。一个是PocketPC应用程序的安装程序,它调用自定义代码来启动ActiveSync应用程序;另一个是Windows桌面版本的安装程序。

在继续之前,我想向一个我使用了多年并决定编写替代品的出色程序致敬。这个程序是 TreePad,由 Henk Hagedoorn 编写。我还要感谢CodeProject和所有贡献者,感谢他们为.NET和C#信息方面最棒的资源之一所付出的辛勤工作。

ForestPadDesktop或ForestPadCE可以独立使用。当与ForestPadService结合使用时,它们会变得更加强大,ForestPadService允许PocketPC和桌面应用程序通过Web通信并同步数据。

目前,同步功能仅检查哪个ForestPad文档较新。这意味着如果您在两个客户端上编辑了同一个ForestPad文档,然后分别从每个客户端同步,则可能会丢失数据。相反,您必须在“断开连接”模式下工作。例如,如果您正在现场编辑PocketPC上的数据,您必须先将数据同步到ForestPadService,然后在ForestPadDesktop中编辑同一文档之前进行同步。

这种简单的方法对我来说效果很好,但也可以通过多种方式进行扩展。您可以添加一个类似于源代码管理的检入/检出系统,您可以同步节点级别的数据,或者任何适合您需求的方法。如果您一直连接到互联网,您甚至可以使同步自动化。如果您只使用其中一个客户端,您仍然可以使用ForestPadService进行备份。ForestPadService不依赖于数据库,因此您可以在支持.NET Framework的任何托管帐户上安装它。

背景

我决定编写ForestPad,以便存储所有我需要回忆的文本信息。以下是我使用它的方式:

我用它来存储歌词。在练习吉他时,我可以快速翻阅歌曲的吉他谱。(Ctrl-K) 可以将光标移到搜索框,就像 FireFox 一样,让我只需通过多次按回车键就可以快速搜索ForestPad文档中的某个项目。

我用它来存储C#代码片段。这是允许的,因为底层文件格式是带有CDATA部分的XML。目前唯一无法存储的是包含CDATA标签的XML片段。

在工作中,我存储IP地址、URL、联系人、有趣的编程文章、电子邮件地址、待办事项列表、电子邮件文本,等等。只要是文本且值得存储和检索,它都会进入ForestPad。我还将其用作便携式互联网收藏夹应用程序。要导入URL,只需将其从浏览器拖放到ForestPad桌面应用程序上。目前,链接不可点击,因为我实现了TextBox控件而不是RichTextBox控件。做出这个决定是因为.NET CF还没有提供RichTextBox(尽管我了解到可以通过非托管代码访问类似的东西)。您还可以将文本从其他程序拖放到TreeView、主TextBox和图形按钮上。在ForestPadDesktop中,您还可以选择一段文本或整个节点,如果您已经在“设置”部分输入了SMTP服务器和“发件人”地址,则可以通过电子邮件发送文本。

ForestPad的设计决策

TreePad一直让我感到困扰的一件事并非TreePad的缺点,而是我自己的组织能力问题。我总是将信息隐藏在层级结构中太深,以至于我“丢失”了它。此外,还有一个根节点,出于某种无法解释的原因,它从图形的角度让我感到不适。我决定遵循一个严格的范例,既消除了根节点,又限制了层级结构。在每个ForestPad文档中,有多个森林,每个森林可以包含多个树、分支和叶子。我认为这种有限的层级结构也使PocketPC版本更容易使用。此外,我决定通过显示节点中第一个回车符之前的所有文本来自动命名TreeView节点的Text属性。这使得在PocketPC上输入更快,因为无需命名节点,并且可以轻松构建大纲而无需最小化InputPanel

TreePad的文件格式对我来说有些奇怪,但必须考虑到它是在1995年左右设计的。每个节点都有一个数字表示其在树中的级别,并使用以下字符串终止。

<end node> 5P9i0s8y19Z

我想 Mr. Hagedoorn 认为序列 5P9i0s8y19Z 不太可能出现在节点文本中,而且我认为这可能是正确的,因为我在使用 TreePad 的时候从来没有遇到过问题。

一个带有根节点和一个子节点的 TreePad 文件看起来像这样:

<Treepad version 2.7>
dt=Text
<node>
name
0
<end node> 5P9i0s8y19Z
dt=Text
<node>
name
1
text
<end node> 5P9i0s8y19Z

有关处理另一种文件格式的有趣代码,请查看TreePadConverter类。我包含了一个TreePad示例文件,以便您了解其工作原理。我所知道的唯一限制是,TreePad文件必须只有5个级别深度(一个根节点和四个级别),以便可以将其映射到森林、树、分支、叶子的格式。TreePad文件的根节点不会被保留。如果您以前没有使用过Stack,并且对它的一个用途感到好奇,那么它将特别值得关注。(注意:TreePadConverter仅在“TreePad 2.7 版本”文件上进行了测试)

我希望使用XML来存储ForestPad文件,这样我就可以将数据导入其他程序,并且在用 UltraEdit 打开时,文件可以保留其视觉层级结构。

因此,与TreePad相比,ForestPad的文件格式看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<forestPad
    guid="6c9325de-dfbe-4878-9d91-1a9f1a7696b0"
    created="5/14/2004 1:05:10 AM"
    updated="5/14/2004 1:07:41 AM">
<forest 
    name="A forest node"
    guid="b441a196-7468-47c8-a010-7ff83429a37b"
    created="01/01/2003 1:00:00 AM"
    updated="5/14/2004 1:06:15 AM">
    <data>
    <![CDATA[A forest node
        This is the text of the forest node.]]>
    </data>
    <tree
        name="A tree node"
        guid="768eae66-e9df-4999-b950-01fa9be1a5cf"
        created="5/14/2004 1:05:38 AM"
        updated="5/14/2004 1:06:11 AM">
        <data>
        <![CDATA[A tree node
            This is the text of the tree node.]]>
        </data>
        <branch
            name="A branch node"
            guid="be4b0993-d4e4-4249-8aa5-fa9c940ae2be"
            created="5/14/2004 1:06:00 AM"
            updated="5/14/2004 1:06:24 AM">
            <data>
            <![CDATA[A branch node
                This is the text of the branch node.]]></data>
                <leaf
                name="A leaf node"
                guid="9c76ff4e-3ae2-450e-b1d2-232b687214aa"
                created="5/14/2004 1:06:26 AM"
                updated="5/14/2004 1:06:38 AM">
                <data>
                <![CDATA[A leaf node
                    This is the text of the leaf node.]]>
                </data>
            </leaf>
        </branch>
    </tree>
</forest>
</forestPad>

文档中的每个项目都包含一个Guid、一个创建日期和一个更新日期。文本包含在“data”节点内的CDATA部分中。可以向ForestPad文件格式添加其他元素或属性,以实现更丰富的功能。

您可以通过单击其中一个图标按钮向TreeView添加节点。ForestPad会将节点添加到当前选定项目的相对位置。节点可以在ForestPadDesktop中重新排列,但目前不能提升或降级。要删除节点,请右键单击它并选择“删除”,或者在ForestPadCE中,将触笔按住节点直到出现上下文菜单。

文档存储在两个平台上的“\My Documents\ForestPad”中。

设计目标总结

总的来说,我的设计目标是创建一个比TreePad更简单但功能相似的程序,并存在一些根本性的区别。

  • 基于XML的文件格式
  • 有限的节点层级
  • 节点的自动命名
  • 文本信息的拖放
  • PocketPC和桌面版本
  • 从ForestPadDesktop内部通过电子邮件发送文本片段
  • 使用Web服务同步(和备份)数据
  • 对不同风格用户界面的尝试

关于代码

ForestPadDesktop和ForestPadCE共享一些代码。它位于ForestPadUtilities项目中。您会注意到有几个类名为xxxxxDesktop和xxxxxCE。这些类之间的差异很小,代码本可以用编译器开关组合起来。这种方法的缺点是代码重复。优点是它使构建过程更顺畅。希望Microsoft在下一个版本中能提供对Compact Framework的明显补充,例如Guid类。使用/unsafe指令进行编译与托管代码的概念相悖。

如果您以前没有使用过TreeView,请查看ForestTreeNode类以及ForestDesktop.cs或ForestCE.cs中的PopulateTreeView方法,在那里您可以看到一个ForestTreeNode对象放置在附加到每个TreeView节点的Tag中。这个Tag包含指向XmlDocument中相应节点的指针,并提供了一种机制来保持TreeViewXmlDocument的同步。

public enum ForestType
{
    Forest = 0,
    Tree = 1,
    Branch = 2,
    Leaf = 3
}

namespace ForestPadUtilities
{
    /// <summary>
    /// Summary description for ForestTreeNode.
    /// </summary>
    public class ForestTreeNode
    {
        public ForestType NodeType;
        public string NodeName;
        public XmlNode NodePointer;
        public string NodeGuid;
        public string NodeCreated;
        public string NodeUpdated;

        public ForestTreeNode()
        {
        }
    }
}
        

目前,您必须下载源代码才能安装ForestPadService。稍后,我可能会构建一个安装程序。

为了完整地构建代码,您需要在“\ForestPadCE\BuildCabs\”中修改BuildCab.bat文件,以反映您的驱动器上的文件位置。简化的命令行如下:

cabwiz.exe ForestPadCE_PPC.inf /dest \ForestPad\ForestPadCE_Setup /err
    Logfile.log /cpu ARMV4 ARM SH3 MIPS X86 WCE420X86

您还需要修改ForestPadCE_PPC.inf并更新路径。请阅读CodeProject文章 Developing and Deploying Pocket PC Setup Applications 以获取更多信息。

首先在Debug模式下构建,然后在Release模式下构建。我用空的文本文件替换了ForestPadCE_Setup项目中的CAB文件以节省空间。它们将在第一次Release构建期间被实际的CAB文件替换。

此解决方案需要设置一个虚拟目录。将虚拟目录指向ForestPadService目录。授予ASPNET进程对ForestPadService\DATA文件夹的完全权限。然后访问 https:///ForestPadService/Login.aspx,输入用户名:admin,密码:admin。

编辑admin用户并创建新密码。然后,在ForestPadCE或ForestPadDesktop的“设置”部分,将https:///ForestPadService/ForestPadService.asmx设置为Web服务URL,将admin作为您的用户名,并输入您新创建的密码。保存更改,创建一个文档,输入一些文本,然后选择“同步”。

您的数据将从客户端传输到ForestPadService。

安全

ForestPad目前的安全措施非常有限。在设计程序时,这不是我的主要关注点。ForestPad Web服务的密码在每个应用程序中都被加密,但目前存储在ForestPad Web服务上的数据未加密,并且密码以明文形式传输到Web服务。向事务添加加密将是一项相对简单的任务。此外,将ForestPad文档存储在数据库中或加密XML也很容易。

您还可以加密ForestPadCE和ForestPadDesktop客户端上的信息。我选择不这样做,因为我希望能够用文本编辑器打开文档。如果您存储敏感信息,我建议确保您的PocketPC和桌面计算机都设置了密码保护。就目前而言,除非您修改ForestPadService以包含加密,否则存储文档可能会使您处于风险之中。

将来,我将在 ForestPad.com 上发布一个源代码版本,可用于远程存储安全信息。

已知未解决的问题

ForestPadCE
  • 有时“设置”窗体而不是主窗体显示。似乎在打开和关闭“设置”窗体,然后最小化应用程序并使用“开始”菜单中的图标将其最大化后发生。
  • “最近使用的程序”菜单中图标未显示的问题
ForestPadDesktop
  • 桌面版本中奇怪的调整大小问题 - 在我的系统上,每次启动时它在垂直方向上会增长19像素。在其他系统上,行为不可预测。
ForestPadService
  • 目前,ForestPad使用“最后更新日期”进行同步。这意味着如果数据在两个位置(例如ForestPadCE / ForestPadDesktop)被编辑然后从两个位置同步,则数据可能会丢失。编辑时间最长的文件的将被覆盖。

可能的原因:

此代码可作为许多不同类型项目的 dasar(基础)。

例如:

您可以为ForestPad用户添加一个只读属性,并为办公室里的每个人设置相同的用户名和密码,以便他们都能接收您创建的ForestPad文档。您可以更进一步,允许ForestPad用户存储他们特定的用户文档,同时仍然接收只读的联合文档。或者,修改ForestPadService,将一组用户创建的所有文档直接重定向给您,作为一种数据收集机制。

在ForestPadCE中添加一个选项,将ForestPad文档存储在可移动内存卡上。

可以添加一个搜索选项,该选项可以搜索所有ForestPad文档,而不仅仅是当前打开的文档。您还可以扩展现有搜索以支持正则表达式。

您可以构建一个基于Web的ForestPad文档查看器或编辑器。

或者,您可以实现一个选项,通过IR在两个PocketPC之间传输ForestPad文档。

特别感谢

四个节点级别的图像由我的朋友Sean Kabanuk设计。

参考文献

这些资源在构建ForestPad的过程中已被证明是有用的
© . All rights reserved.