ASP.NET可交互式位图窗体设计(9)

asp.net|交互|设计

在页面和请求之间传递状态
    为使应用程序能够工作,它需要能够维护请求之间的状态并将状态传递给绘图页面(如下所示)。
  
    维护和传递状态有多种方式。如果应用程序是严格的单页面应用程序(和以前的应用程序一样),则可以使用视图状态,其中数据被编码存储在 Web 页的隐藏输入字段中。
  
    但是我们的图像控件是在单独的页面中进行绘图的,因此需要某些更灵活的东西。最好的选择就是 cookie 和会话状态。会话状态非常灵活,但要求使用服务器资源。浏览器可以保留 cookie,但其大小非常有限。
  
    Page_Load
    Page_Load 是在创建页面对象之后以及在运行所有事件处理程序之前被调用的。因此 Page_Load 方法是加载永久数据的理想所在。如果找不到数据,就创建新的数据。以下是相关代码:
  
  
  Private Sub Page_Load(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) _
  Handles MyBase.Load
  randomGen = ViewState("randomGen")
  If randomGen Is Nothing Then randomGen = New Random()
  ' 选项之一:使用会话状态获得绘图列表
  '(保存在 Page_Unload 中)
  '(注意:要求服务器上的状态存储)
  drawingList = Session("drawingList")
  If drawingList Is Nothing Then drawingList = New DShapeList()
  ' 选择之二:从用户浏览器上的 cookie 中
  ' 检索绘图状态
  '(注意:不需要服务器存储,但有些用户会禁用 cookie)
  '(注意之二:cookie 不会自动反序列化!:( )
  ' 注意之三:使用 cookie 将限制能够绘制的形状数量
  'Dim drawingListCookie As HttpCookie
  'drawingListCookie = Request.Cookies("drawingList")
  'If drawingListCookie Is Nothing Then
  ' drawingList = New DShapeList()
  'Else
  ' drawingList = _
  ' SerialHelper.DeserializeFromBase64String( _
  ' drawingListCookie.Value)
  'End If
  End Sub
  
    首先,我们尝试从视图状态加载随机数发生器状态。如果存在,则使用存储的值。如果不存在,则创建一个新的 Random 对象。
  
    接下来,我们尝试从会话状态加载绘图列表。同样,如果不存在绘图列表,则创建一个新的空列表。
  
    如果需要,视图状态和会话状态都会自动序列化我们的对象。视图状态始终被序列化,因此可以表示为浏览器隐藏输入字段中的编码的字符串。会话状态当存储在数据库中或者在服务器间进行传递时被序列化,但是如果应用程序运行在单个服务器上(例如在开发机器上进行测试时),则不会将其序列化。
  
    被注释的代码试图从 cookie 加载绘图列表。请注意,处理 cookie 要比处理视图或会话状态复杂得多。首先就是不能自动序列化。为序列化为一个字符串,我们在一个新类当中编写了 helper 函数,如下所示:
  
  
  Public Shared Function DeserializeFromBase64String( _
  ByVal base64String As String) As Object
  Dim formatter As New BinaryFormatter()
  Dim bytes() As Byte = Convert.FromBase64String(base64String)
  Dim serialMemoryStream As New MemoryStream(bytes)
  Return formatter.Deserialize(serialMemoryStream)
  End Function
  
  
    Dr. GUI 使用了二进制格式化程序并转换为可打印的 base 64 字符串,因为无论是 SOAP 还是 XML 格式化程序都不适用于此应用程序。我们必须从纯二进制表示转换为 base 64 字符串,以避免因简单复制字节而产生字符串中控制字符的潜在问题。base 64 字符串使用一个字符 A-Z、a-z、0-9、+ 或 /(共 64 个或 2^6 个字符)来表示二进制字符串中的每六位,因此四个字符表示三个字节 -- 第一个字符表示第一个字节中的六位,第二个字符表示第一个字节的末两位和第二个字节的前四位,以此类推。同样,使用 base 64 字符串关键在于可以将字符串限制为可打印字符,这样就避免了任何控制字符出现潜在问题。
  
    XML 格式化程序不会序列化私有数据 -- 而 Dr. GUI 也不打算为绘图列表中的私有数据添加公开访问权限。SOAP 格式化程序不存在这种限制,但它不会序列化空列表以便进行反序列化。相反,它不为空列表向数据流写入任何东西,这样当尝试反序列化时就会引发一个异常。(Dr. GUI 认为这是一个错误。)
  
    Dr. GUI 更喜欢以可读的 XML 格式进行序列化,但由于两种 XML 序列化格式化程序都无法完成此项工作,所以最终选择了二进制格式化程序并转换为 base 64 字符串。
  
    Page_Unload
    Page_Unload 是在破坏页面对象(包括任何所包含的数据)之前被调用的,因此是永久放置重要数据的理想位置,这样我们便可以在将来从 Page_Load(或者从图像的 Page_Load)中取出这些数据。
  
    因此,我们将数据保存在 Page_Unload 中,并从 Page_Load 中检索数据。虽然这有些奇怪,但却是正确的。
  
    以下是 Page_Unload 的代码:
  
  Private Sub Page_Unload(ByVal sender As Object, _
  ByVal e As System.EventArgs) _
  Handles MyBase.PreRender
  ViewState("randomGen") = randomGen
  ' 选项之一:编写会话状态
  Session("drawingList") = drawingList
  
  ' 选项之二:编写一个 cookie。必须编写代码进行序列化。
  ' 注意:使用 cookie 将限制能够绘制的形状数量!
  'Dim drawingListString As String =
  ' SerialHelper.SerializeToBase64String(drawingList)
  'Response.Cookies.Add(New HttpCookie("drawingList", _
  ' drawingListString))
  End Sub
  
  
  
    此代码稍微有些简单,因为我们不必查看状态是否已经存在于视图或会话状态对象中,而只需将其无条件写出。
  
    同样,视图状态和会话状态可以自动对自身进行序列化,而 cookie 则不能,因此我们需要亲自执行。Dr. GUI 编写了下面的 helper 函数(在单独的类中),代码如下所示:
  
  
  Public Shared Function SerializeToBase64String(ByVal o As Object) _
  As String
  Dim formatter As New BinaryFormatter()
  Dim serialMemoryStream As New MemoryStream()
  formatter.Serialize(serialMemoryStream, o)
  Dim bytes() As Byte = serialMemoryStream.ToArray()
  Return Convert.ToBase64String(bytes)
  End Function
  
    在单独的页面中绘图
    正如前面提到的,绘图是在单独的页面中进行的。以下是该页面的代码:
  
  
  Private Sub Page_Load(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Load
  Dim drawingList As DShapeList
  ' 获取绘图列表选项之一:使用会话状态...
  drawingList = Session("drawingList")
  If drawingList Is Nothing Then drawingList = New DShapeList()
  
  ' 获取绘图列表选项之二:使用 cookie...
  '(请查看主页代码以了解更多注释)
  'Dim drawingListCookie As HttpCookie
  'drawingListCookie = Request.Cookies("drawingList")
  'If drawingListCookie Is Nothing Then
  'drawingList = New DShapeList()
  'Else
  ' drawingList = _
  ' SerialHelper.DeserializeFromBase64String( _
  ' drawingListCookie.Value)
  'End If
  
  Response.ContentType = "image/gif"
  Dim bitMap As New Bitmap(368, 376)
  Dim g As Graphics = Graphics.FromImage(bitMap)
  Try
  g.Clear(Color.White)
  drawingList.DrawList(g)
  bitMap.Save(Response.OutputStream, ImageFormat.Gif)
  Finally
  g.Dispose()
  bitMap.Dispose()
  End Try
  End Sub
  
  
    首先,我们从会话状态或 cookie 中获取绘图列表。(这部分代码与上面的 Page_Load 方法类似。)
  
    然后,我们将正在编写的响应流的 ContentType 设置为一个 GIF 图像。
  
    接下来,我们要做一些真正美妙的事情:按照所需的大小(本例按照与 Windows 窗体应用程序中相同的大小)创建一个位图。
  
    然后,我们得到一个与该位图相关联的 Graphics 对象,清除该对象,并在其中绘制我们的列表。
  
    下面的步骤很重要:接下来,我们将 GIF 格式的图像内容写出到响应流(即浏览器)中。我们设置了这种响应类型以确保浏览器能够正确解释图像,然后发送图像的位。(.NET Framework 使该操作变得相当简单。而在原来的 Windows GDI 时代,仅在位图上进行绘制都是非常痛苦的!)
  
    另一个重要步骤就是要记住清理 Graphics 和 Bitmap 对象 -- 并使用 Try/Finally,以便即使出现异常也会清理对象。
  
    嗨!步骤真多。但是为了让此应用程序能够作为 ASP.NET 应用程序运行,还是值得的 -- 并且更好的是,这种应用程序不需要依赖客户端脚本。
  
    试一试!
  
  
    如果您手头有 .NET,学习它的最好方法就是试一试。如果没有,就请想办法得到。如果您每周在 Dr. GUI .NET 上花费一个小时左右,那么在了解 .NET 之前您将已经成为一名 .NET Framework 专家了。
  
    从您开始 -- 并邀请您的朋友!
    作为第一个学习新技术的人,感觉一定不错,但如果和朋友们分享则乐趣更多!为享受更多乐趣,邀请朋友共同学习 .NET 吧!
  
    应进行的尝试...
    首先试一下这里给出的代码。其中有一些是从大型程序中节选下来的,围绕这些代码片断创建程序会取得不错的效果。(如果必须,也可以使用 Dr. GUI 提供的代码。)琢磨一下代码。
  
    向绘图程序添加一些不同的形状,包括填充和不填充的形状。注意:虽然我们没有对其进行转换,但所添加的类可能存在于来自其他文件的不同程序集中(因而是不同的可执行文件)。这意味着所添加的类的语言甚至可以和其他类不同。当您阅读并尝试有关的必要工作后,会更加确信这一点。
  
    请向这里的类添加一些方法,并尝试改动用户界面。自己制作一个可爱的 CAD 小程序。
  
    在自己选择的项目中使用继承、abstract/MustInherit 类、接口和多态。当类系列具有很多共同部分时,使用继承的效果最佳。如果类并不具有很多共同部分,但功能相似,这时使用接口的效果最好。
  
    尝试用 ASP.NET 编写自己的绘图应用程序。请注意,如果能够运行 .NET Framework,则只需 Microsoft Internet Information Server (IIS) 便可以在自己的计算机上运行 ASP.NET -- 无需服务器!Dr. GUI 认为,在便携式计算机上仅使用标准操作系统和免费的 .NET Framework 创建和测试 Web 应用程序,感觉实在好极了。(但 Dr. GUI 还是倾向于使用 Visual Studio,或者至少 Visual Basic 或 Microsoft Visual C#? 标准版。)看看吧!不需要服务器!甚至不需要 Internet 连接!(可在 Brand J 的扩展版上尝试…) 
  

时间: 2024-11-05 06:25:36

ASP.NET可交互式位图窗体设计(9)的相关文章

ASP.NET可交互式位图窗体设计(3)

asp.net|交互|设计 构造函数    构造函数传递三个参数:包含圆的中心坐标的点.圆的半径以及一个 System.Drawing.Color 结构(包含用于绘制圆轮廓的颜色).       然后我们根据中心和半径计算边框,并将笔颜色项设置为我们传递的颜色对象.       绘图代码    Draw 方法重载实际上非常简单:它根据我们保存在构造函数中的颜色对象创建一个笔对象,然后使用该笔,调用 Graphics.DrawEllipse 方法绘制圆,同时传递了我们早先创建的边框.      

ASP.NET可交互式位图窗体设计(4)

asp.net|交互|设计  绘图如何改变    您会注意到,Draw 方法与基类基本相同 -- 主要差别在于它调用了 Fill 方法,因为要完成绘制一个填充对象,所以需要对其进行填充.我们没有为绘制轮廓重写代码,而是再次调用了基类的方法:Visual Basic .NET 中的 MyBase.Draw(g) 或 C# 中的 base.Draw(g);.       因为我们正在指派用于绘制轮廓的笔,因此需要使用 using 或 Try/Finally 和 Dispose 以确保迅速释放 Win

ASP.NET可交互式位图窗体设计(6)

asp.net|交互|设计 使我们的对象可序列化    为在 ASP.NET 中使用可绘制对象类,我们需要对其再进行一项更改.这些类需要是可序列化的,以便能够在主要的 Web 页和生成该图像的 Web 页之间传递数据(后面将详述).序列化是这样的过程:将某个类的数据以某种方式写入存储介质,以便存储和/或传递数据并在以后反序列化.反序列化是从序列化数据中重新创建对象的过程.我们会在将来的专栏中深入讨论这个问题.       Dr. GUI 最开始作为 Windows 窗体应用程序编写此应用程序时,

ASP.NET可交互式位图窗体设计(7)

asp.net|交互|设计 在 Windows 窗体应用程序中使用可绘制对象    我们已经讨论了可绘制对象类,下面谈谈如何在 Windows 窗体应用程序中使用这些类.首先谈一下 Windows 窗体应用程序是怎样工作的.       Windows 窗体应用程序的主要部分    简单的 Windows 窗体应用程序包含一个主窗口(或窗体),其中包含控件子项.如果您是一位 Visual Basic 程序员,就会发现这个模型非常熟悉.       主窗口    任何 Windows 窗体应用程序

ASP.NET可交互式位图窗体设计(8)

asp.net|交互|设计 按钮单击事件处理程序    接下来就是每个按钮的按钮单击事件处理程序.多数仅仅是向绘图列表中添加一个新的可绘制对象,然后调用 PictureBox 上的 Invalidate,从而使用更新的绘图列表进行重绘.典型的按钮事件处理程序代码如下所示:          C#   private void AddPoint_Click(object sender, System.EventArgs e) {   drawingList.Add(new DPoint(GetRa

ASP.NET可交互式位图窗体设计(2)

asp.net|交互|设计 我们的任务    这个程序的基本思想如下:我们有一个 abstract 基类(在 Microsoft Visual Basic? 中是 MustInherit),其中包含公共数据(如边框)和一套虚拟方法,虚拟方法多数是抽象的(在 Visual Basic 中是 MustOverride),例如 Draw.请注意,Draw 的多态性很重要,因为每个可绘制对象类型(如点.线.矩形.圆等)都是用完全不同的代码绘制的.       虽然方法可以是多态的,但数据不能.因此,我们

ASP.NET可交互式位图窗体设计(5)

asp.net|交互|设计 维护两个列表    因为我们要改变对象的填充颜色以实现 Change fill to hot pink 按钮,因此维护了两个可绘制对象列表:一个列表是全部对象,另一个列表是可填充对象.我们为这两个列表都使用了 ArrayList 类.ArrayList 对象包含一组 Object 引用 -- 这样一个 ArrayList 可以包含系统中任何类型的混合.       这实际上并没有什么帮助 -- 我们希望 ArrayList 仅仅包括可绘制/可填充对象.为此,我们将 A

ASP.NET创建Web服务之设计方针

asp.net|web|web服务|创建|设计 使用ASP.NET构造一个简单的XML Web服务是相对容易的,然而,XML Web服务的真正的强大的功能只有等你研究了基础结构以后才能领悟.XML Web服务是建立在.NET框架和公共语言运行时间基础上的.一个XML Web服务可以利用这些技术.例如,ASP.NET支持的性能.状态管理和验证全都可被用来构造XML Web服务. XML Web服务的基础结构是构建来符合象SOAP.XML和WSDL这样的行业标准,并且它允许其他的平台的客户端与XML

怎样在asp.net中嵌套winform窗体?

问题描述 怎样在asp.net中嵌套winform窗体?然后通过winform窗体来连接RFID来实现对读卡器进行读卡和写卡 解决方案 解决方案二: 解决方案三:两种方式1.ActiveX前提是浏览器认为你的控件是安全的2.WebBrowser自制浏览器用ObjectForScripting赋予脚本读写卡的方法然后Asp.Net里用脚本的external调用解决方案四:怎样在asp.net中嵌套winform窗体?答:不能.解决方案五:在server端引用之后调用部分功能是可以的.但在serve