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

抽奖(圣诞节抽奖应用程序)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (10投票s)

2009年1月28日

CPOL

17分钟阅读

viewsIcon

68535

downloadIcon

626

一个使用DHTML、JavaScript、XML、C#、Forms、VS2008、.NET 3.5、加密的圣诞节抽签应用程序。

代码

下载.Zip文件后,您必须将其解压缩。例如,如果您解压缩到目录c:\NameDrawing,您将获得一个文件夹和文件树,如下所示

根文件夹仅包含一个文件NameDrawing.sln,这是VS2010的解决方案文件。在该文件夹中,有一个子文件夹c:\NameDrawing\NameDrawing,其中包含所有项目文件和项目子文件夹。其中最有趣的是c:\NameDrawing\NameDrawing\DataFiles_2011文件夹。如果您决定使用此项目,那么该文件夹中的所有.html文件以及单个 .jpg文件 和名为Crypt.js的文件将成为项目的最终结果。特别是名为index.html的文件是参与抽签活动的人员将在其Web浏览器中打开的文件。

简述

  • 该项目包含一个VS2010 C# Forms应用程序的源代码,该应用程序会编写一个客户端JavaScript文件,其中包含一个函数,该函数从index.html文件中执行。该应用程序使用XML数据文件作为输入。示例文件:index.htmldrawing_names.xmlWish-Lists.html已包含在内。
  • 要在“现实世界”中使用此项目,您需要
    1. 编译C# VS2010项目(生成可执行文件)
    2. 编辑drawing_names.XML数据文件(引入真实用户姓名和密码短语)
    3. 编辑index.html文件(引入真实用户姓名)
    4. 编辑“附加”的wishlists.html(引入真实用户姓名)
    5. 运行应用程序(生成JavaScript)
    6. 将所有文件发布到某个网站

要查看2008年圣诞节期间的“工作版本”结果,请访问:http://papa.poemy.net/2008_Drawing_Names/index.html

现在写完这些,似乎工作量很大,但考虑到这个应用程序将在圣诞节期间使用,如果您想在2012年圣诞节期间为您的家人或朋友使用,您还有几个月的时间来准备。

注意:我不是一个有成就的GUI设计师或超级OO设计师。我的现实世界才能在于中间件、通信和操作系统内部设计与实现。

这个项目中的东西对我来说纯粹是爱好/乐趣。这意味着这个项目中的100%技术都是纯粹的“黑客”,我不是靠这个谋生。所以……这意味着,无论您对这个项目有什么看法——您很可能是正确的(好的、坏的、丑陋的、其他的)。

另外,我认为评论/更改等……很棒,也受到欢迎和接受。我认为在CodeProject上工作时,也有协作的能力,所以最终的最佳结果是应用程序足够有趣,能够激发这种行为。我知道我有很多关于修改它的想法。我将在此发布更改和扩展,如果它们变得足够大,也可能在新文章中发布。

引言(动机)

在大家庭中,我们小时候总是从帽子里抽签,而不是给每个兄弟姐妹买礼物。然后,在我们长大成人后,我们继续了这个传统,并进一步将配偶也包括进来。随着时间的推移,抽签活动变成了感恩节活动,有时甚至是夏季海滩之旅。关于不抽到自己名字或配偶名字的讨论很多,也有很多放回去重抽的情况等等。当然,我无法抵挡诱惑,决定编写一个应用程序来模拟随机抽签,保留过去抽签的历史,并强制执行不抽到自己名字或配偶名字的规则。随着时间的推移,甚至还可以添加“作弊”功能,当有人当年就是想抽到另一个人的名字时。

背景

最初的CodeProject版本是在2009年完成的。自那时以来,收到了增强请求和错误报告,因此2011年的这个版本代表了实现更改和修复错误所做的修改。

复杂性级别

对我来说,如果我以前从未做过某件事,那它就是复杂的。如果我能找到一个用我能理解的语法编写的例子,我通常就能“弄明白”。我会看着它,知道所有的语法元素,知道它做了什么,通常会说,“哦,是的,我明白了。”或者“啊哈!”原来是这样做的。如果您在阅读过程中遇到任何点,想知道“他在做什么?”那么请评论这篇文章,我会尝试写一些关于这方面的内容,无论是作为对评论的回应,还是添加一节到整篇文章中。您不必具体说明,可以问一些全局问题,当然也可以问具体问题。

使用应用程序

该应用程序的作用如下:它编写一个名为“Crypt.js”的JavaScript文件,可以被网页引用。项目的组成部分包括网页“index.html”的示例、其背景.jpg文件以及一些示例“愿望清单页面”。要使用此项目,您需要根据需要编辑示例index.html页面和示例“愿望清单页面”。

要使用实际进行抽签活动的应用程序,您需要编辑示例.XML文件,并插入与参与抽签活动的人员相匹配的内容。您可以(如果可用)甚至添加历史记录,甚至为抽签活动添加一些“作弊”功能。

更新.XML文件后,通过按下GUI中的按钮来执行应用程序。要测试结果,请加载index.html并输入密码短语,然后按名称按钮。

关于数据

应用程序的输入数据排列在一个.XML文件中。我实际上是在创建.XSD文件之前就编写了该文件。VS2010有一个很好的功能,它可以提取一个看起来像样的.XSD文件来配合XML文件。完成之后,我会修改XML,并记住相应地修改XSD。下图说明了XML的结构(该图由VS2010创建)。

Drawing_Names/schema.png

工作原理

最终对象是一个名为“index.html”的网页,您将其与支持脚本文件“Crypt.JS”以及其他支持的.html文件(愿望清单)和背景.jpg文件一起发布到网络上的某个位置。然后,您邀请参与抽签活动的人员访问该网站。

每个人输入其“密码短语”,然后按其“按钮”。此操作会将密码短语发送到JavaScript,JavaScript会解密该用户的两条消息。第一条消息告诉用户他们抽到了谁的名字,第二条消息告诉用户他们是否是“秘密圣诞老人”,如果是,则他们应该为谁准备额外礼物。

页面上的其他按钮会打开参与者的“愿望清单”。当然,在开始这一切之前,您需要收集参与者的姓名和密码短语以及其他信息,并将其输入到.XML文件中,并相应地编辑.HTML文件,以便每个参与者的按钮上都有他的名字。此外,随着活动的进行,您可以更新与每个参与者关联的“愿望清单”.html文件,因为他们会把愿望清单的内容发送给您,管理员(哎呀……这又是一个应用程序功能的主题,即让用户自己完成所有这些工作)。

关于应用程序结构

该应用程序是使用Visual Studio 2008 C# Windows Forms向导创建的。这个向导会弹出一个空白窗口,您可以在其中放置控件。此应用程序围绕您可以按下的按钮(控件)而设计。接下来是对应用程序的高层讨论,以您可操作的控件来阐述。更技术性的讨论将在此高层讨论之后。

  • 加载XML文件 - 此操作会打开一个“文件夹浏览器对话框”,允许操作员找到包含数据文件的文件夹。找到文件夹并关闭浏览器对话框后,会打开并解析.XML文件,填充应用程序中的数据值。如果选中名为“显示结果”的复选框,应用程序会在列表框中显示数据值。这是应用程序在单击“加载XML文件”按钮后显示的屏幕截图。
  • 抽签 - 在“加载XML文件”执行后,此操作将被启用。此操作将执行上述“抽签”操作。由于此操作模拟“随机抽取”,可能会出现“帽子底部”的情况,您发现自己的名字,或者另一个您不能使用的人的名字,比如您的配偶,或者您几年前抽到的名字。所以在这种情况下,您需要重新开始。逻辑设计为最多重试100次,然后以失败告终。您可以在XML文件中放入足够的历史记录,以至于不可能有解决方案。在这种情况下,您需要删除一些历史记录或调整作弊/配偶关系。
  • 注意:您可以分析.xml文件,以确定今年的解决方案是否可行。这种分析就像是进行一次“从帽子里抽签”的活动,但没有任何随机性。一种方法是遍历数据(包括历史记录和规则),并选择第一组有效的姓名配对。在这种组合方法中,您也可能到达“帽子底部”,发现没有可能的解决方案,在这种情况下,该函数将直接返回值“调整规则/历史记录,无解决方案”。

  • 写入脚本 - 在“抽签”操作执行后,此操作将被启用。此操作将遍历数据,并使用每个参与者的“密码短语加密与之相关的消息。加密技术是唯一存在的完美加密技术,即将密码短语与明文进行XOR运算。XOR运算的特点是,如果应用两次则会撤销自身。如果密码短语是一个随机字符串,它会将明文还原为随机字符串。在密码学中,这被称为“一次性密码本”。在所有消息都加密后,“写入脚本”操作将创建名为“Crypt.JS”的Java脚本。该脚本由三个部分组成:顶部、中部和底部。顶部是Java过程的开头语句。中部是使用XOR加密创建的加密文本的数组。底部是Java函数的逻辑。Java函数将密码短语与加密消息进行XOR运算,并将产生的明文放入.htm文件的文本框中。密码短语不在Java脚本或index.html文件中,因此如果有人忘记了他的密码短语,他必须向管理员求助,让他从.XML文件中找出并发送给他。
  • 查看页面 - 在“写入脚本”操作执行后,此操作将被启用,并在浏览器控件中打开index.html文件。按此按钮后,您可以测试网页的运行情况。这是在Web浏览器控件中加载的index.html文件的屏幕截图。
  • Drawing_Names/Screen_003.png

除了控制应用程序的主要按钮外,还有一个标记为“加密”的按钮,以及与之关联的三个文本框。在正确的框中输入明文和密码短语,然后按“加密”按钮,您将在第三个文本框中看到产生的加密文本。此行为独立于应用程序的其余部分,但会调用应用程序的主要部分所调用的相同函数。如果您将加密文本粘贴到明文框中,并使用与加密时相同的密码短语,然后按“加密”按钮,明文将被“解密”。这是这样一个测试的屏幕截图,其中明文被加密。

Drawing_Names/Screen_004.png

这是整个应用程序的类图。名为“publicDATA”的类只是用于将所有公共数据组织在一个地方。所有这些成员都可以声明为在主应用程序中公共,而无需将其封装在自己的类中。

Drawing_Names/ClassDiagram_Graphic.png

一些技术细节

  • loadXMLFile_Click - 这是一个加载XML文件(并设置为验证它)的函数,然后对其进行解析,填充publicData类实例的部分内容。
  • 该函数的工作方式是通过一系列while(Reader.read())循环。在大型外部循环内部,有一组if/then/else语句,用于解码XML文件的主要元素,这些元素是thisYearsSecretSantaMessagethisYearsCheatSheethistoryLognameList。如果启用了显示结果复选框,该函数还会调用displayXMLContent。此外,由于这是第一个被调用的函数,它会初始化随机数生成器。

  • drawNames_Click - 填充今年的姓名,并选择一位秘密圣诞老人及其目标。为了模拟从帽子里随机抽签,值是从一组随机数生成的。doTheNameDrawdoPickSecretSanta这两个函数实际选择值。由于这些函数可能会因为XML文件中的历史记录太多而无法进行有效选择,或者更不太可能发生的情况是,一长串随机数导致失败;drawNames_Click确实考虑了这种失败。如果该复选框处于选中状态,它还将显示结果。
  • 注意doPickSecretSantadoTheNameDraw之前完成,因为内置规则之一是您不能抽取被选为秘密圣诞老人目标的人的名字,假设您是今年的秘密圣诞老人。以下是所有规则:

    • [规则-1] 如果您过去曾是秘密圣诞老人,则本年度不能再次担任。
    • [规则-2] 如果您过去曾是秘密圣诞老人目标,则本年度不能再次担任。
    • [规则-3] 您不能抽取自己的名字(除非是通过作弊,这相当于您选择退出今年的活动)。
    • [规则-4] 您不能抽取配偶的名字(假设名单中有配偶,无多位配偶)。
    • [规则-5] 您不能抽取过去几年抽到的名字(除非通过作弊)。
    • [规则-6] 如果您是今年的秘密圣诞老人,则不能抽取与秘密圣诞老人目标相同的人的名字。
  • writeScript_Click - 对于每个需要加密的消息,此函数调用Crypt函数。之后,函数会写入Crypt.JS文件。
  • bViewPage_Click - 最后,脚本写入完成后,您可以显示index.html文件并对其进行操作。

关于Crypt.JS和index.html

Crypt.js是一个文件,其中包含一个Java脚本函数,该函数“了解”其伴侣index.html的结构。

index.html是一个HTML文件,它由一堆按钮(每个参与者一个)和三个文本框组成;一个用于密码短语,一个用于“这是您抽到的名字。”,一个用于“您今年是(或不是)秘密圣诞老人。”。还有另一组按钮可以“跳转”到“Wish-List.html”页面。

index.html网页可以完全修改。当然,在实际组装“现实世界”版本的所有内容的过程中,您确实会修改index.html文件和wish-lists.html文件。为了配合这些编辑,您将从每个参与者那里收集(或分配给每个人)一个“密码短语”。

一旦您有了每个人的姓名、密码短语、配偶关系(或没有),您就可以修改drawing_names.xml数据文件。您可以自定义每个参与者姓名被抽取时显示的每条消息,您可以自定义每位今年不是秘密圣诞老人的人的消息,以及您可以自定义唯一的秘密圣诞老人消息。请注意,字符串中的特殊字符“$”和“*”会被替换为秘密圣诞老人及其目标的姓名,如果您忘记了它们,秘密圣诞老人消息将无法正常工作。

因此,如果您已经编辑了index.html文件、drawing_names.xml文件并编译了应用程序,那么您就可以运行应用程序,访问.xml数据文件的位置,读取数据文件,进行抽签并写入脚本。该应用程序有一个内置窗口用于查看最终的index.html文件。

关注点

将应用程序转换为C#应用程序的主要动机是转换所有数据到一个可以读取的文件,而不是必须实际编辑源代码。我认为文件格式的逻辑选择是XML。所以,我需要知道如何读取XML文件并让内容填充应用程序的数据。结果是我学到了两件非常有趣的事情。

第一是:使用XMLReader从XML文件中提取信息的方式非常简单(嵌套循环和选择语句)。

第二是:显然.NET 3.5对如何从模式验证XML文件(当元素属性涉及时)一无所知。

注意:关于.NET 3.5

  1. 它坏了,或者
  2. 我没有正确设置模式和/或模式验证逻辑。

历史

  • 新增)---2011年12月04日 - 使用VS2010进行构建。(上传了一个新的.zip文件,并更改了部分文本和图形以反映这一点。添加了一些请求的功能,并修复了一个报告给应用程序的错误。我还更改了.ZIP文件的内容,使其不包含可执行文件。(您现在必须从源文件中进行构建。)
    • 现已使用 --- Visual Studio 2010。
    • 已添加到模式中 --- “作弊”现在有一个作弊类型,它可以是以下之一:
      • MustPick - 这是原始的“作弊”类型,其中某个参与者有一个预定的选择。
      • MustNotPick - 这是一个新的“作弊”,其中某个参与者可能永远不会选择另一个人。
      • TheSecretSantaTarget - 这个“作弊”将秘密圣诞老人目标设置为当年某个参与者的选择。
      • MayNotBeSecretSanta - 这个“作弊”阻止某个参与者成为秘密圣诞老人。

      请注意:如果您目前正在使用该应用程序并希望获得部分新内容,那么您将需要升级您当前的.XSD和.XML文件。

    • 修复了一个错误 -- 与历史数组有关。历史记录的每年都有一个包含该参与者活动的参与者列表。该数组(参与者)通过一个“基于1”的索引来引用,而数组本身是“基于0”的,所以bug修复是通过从索引中减去1来实现的,从而为“基于0”的数组创建了正确的索引。
  • 2009年2月8日 - .zip文件没有变化,我只是添加了“复杂性”段落。
  • 2009年2月7日 - .zip文件没有变化,我只是编辑了此页面的文本。
  • 2009年1月23日 - 初始帖子(嗯,事实上我确实忘记设置“建设中”复选框,甚至收到了一些评论,指出该文章看起来有点未完成)。鉴于您,读者,已经在Code Project上看过一些项目,并且熟悉它们通常的组织方式,请随时留下关于如何改进它的评论。
© . All rights reserved.