注意:Page_Load事件不包含对象引用或是事件参数!
--------------------------------------------------------------------------------
Page.IsPostBack属性
Page_Load子程序在每次页面加载的时候都会运行。如果你只想在第一次加载此页面的时候执行Page_Load中的代码,你可以使用Page.IsPostBack属性。如果Page.IsPostBack属性为false,页面是第一次被加载,如果为true,则页面是被“投递”(post)回服务器的(例如从一个表单中的按钮点击):
上面的例子中,只会在第一次加载此页面的时候写出“The date and time is....”的消息。当用户点击Submit按钮时,submit 子程序会对第二个label写出“Hello World!”,但是第一个label中的日期和时间则不会改变。
--------------------------------------------------------------------------------
每当点击ASP.NET的Web网页上的Button、LinkButton或ImageButton等控件时,表单就会被发送到服务器上。如果某些控件的AutoPostBack属性被设置为true,那么当该控件的状态被改变后,也会使表单会发送回服务器。(AutoPostBack属性,它只有两个bool值,true/false。如果这个属性被设置成false,那么点击后就不会立刻将变化传给服务器处理,也就不会有该控件的SelectedIndexChanged事件。)
每次当表单被发送回服务器,就会被重新加载,启动Page_Load事件,执行Page_Load事件处理程序中的所有代码(注意,是每次都会执行!)。
很显然把网页的初始化代码放在这里是最合适不过。我们经常会希望在每次加载网页时执行一些代码,如一些控件的数据绑定。
当我们希望只有在网页第一次加载时执行另一些代码(基本上都是数据的默认绑定),甚至希望一些代码在除首次加载外的每次加载时执行。那么我们可以利用IsPostBack特性来完成这一功能。在网页第一次加载时,该属性的值是false。如果网页因回送而被重新加载,IsPostBack属性的值就会被设置为true。
在ASP.NET应用程序中,如果需要在页面第一次显示时执行一些初始化操作,必须判断IsPostBack属性!
在ASP.NET使用Page.IsPostback,那么就可以避免往返行程上的额外工作:如果处理服务器控件回发,通常需要在第一次请求页时执行代码,该代码不同于激发事件时用于往返行程的代码。如果检查?Page.IsPostBack?属性,则代码可按条件执行,具体取决于是否有对页的初始请求或对服务器控件事件的响应。这样做似乎很明显,但实际上可以忽略此项检查而不更改页的行为。该属性用的好坏,直接关系到你程序运行是否按照你最初的意愿,也关系到整个页面的效率。因为,如果每次都会给控件绑定数据,不管你是第一次访问,还是提交了数据以后,那么这个页面程序的效率可想而知。
一个B/S结构的页面每一次提交,它都会重新从头到尾执行一次。而C/S结构的程序就不会这样,这是和C/S结构的程序最大的区别!其实,得不到控件的数据,都是因为这个原因。
--------------------------------------------------------------------------------
this.IsPostBack表示是不是回发动作.所谓的回发就是在页面加载以后,在本页有提交服务器的动作.this.IsPostBack == true 表示是回发.
通常使用this.IsPostBack 是不是第一次加载.
一、预备知识—程序的内存分配
2.3申请大小的限制
2.5堆和栈中的存储内容 2.6存取效率的比较 char s1[] = "aaaaaaaaaaaaaaa";
堆和栈的联系与区别dd 在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。 首先,我们举一个例子: void f() { int* p=new int[5]; } 这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下: 00401028 push 14h 0040102A call operator new (00401060) 0040102F add esp,4 00401032 mov dword ptr [ebp-8],eax 00401035 mov eax,dword ptr [ebp-8] 00401038 mov dword ptr [ebp-4],eax 这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete []p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。 好了,我们回到我们的主题:堆和栈究竟有什么区别? 主要的区别由以下几点: 1、管理方式不同; 2、空间大小不同; 3、能否产生碎片不同; 4、生长方向不同; 5、分配方式不同; 6、分配效率不同; 管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。 空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改: 打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。 注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。 碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。 生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。 分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。 从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。 虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。 无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的 :) 对了,还有一件事,如果有人把堆栈合起来说,那它的意思是栈,可不是堆,呵呵, 清楚了? |
http://www.gissky.net/Soft/dzsj/200607/63.html
2. ENVI/IDL二次开发中文培训教程
http://www.gissky.net/Soft/dzsj/200607/58.html
3. ENVI用户指南(中文)
http://www.gissky.net/Soft/dzsj/200607/56.html
4. MapInfo中文版用户指南(精简版)
http://www.gissky.net/Soft/dzsj/200607/55.html
5. 数字地图制图原理
http://www.gissky.net/Soft/dzsj/200607/54.html
6. 《数字高程模型》电子书
http://www.gissky.net/Soft/dzsj/200607/45.html
7. 《Modeling Our World》中文版本
http://www.gissky.net/Soft/dzsj/200607/39.html
8. Visual C++开发GIS系统——开发实例剖析
http://www.gissky.net/Soft/dzsj/200607/38.html
9. 《地理信息系统--原理、方法和应用》
http://www.gissky.net/Soft/dzsj/200607/35.html
10. GIS二次开发-使用Mapobjects
http://www.gissky.net/Soft/dzsj/200607/28.html
11. MicroStation中文培训教材
http://www.gissky.net/Soft/dzsj/200607/25.html
12. 快速制图基本操作-ArcGIS应用案例
http://www.gissky.net/Soft/dzsj/200607/16.html
13. MapX中文应用开发讲义
http://www.gissky.net/Soft/dzsj/200607/22.html
委托和事件在用户界面程序里用的比较的多,比如象在winform或webform的用户UI上的button和它的click事件:
// 将Button1_Click()方法绑定到按钮控件Button1的Click事件上
this.Button1.Click += new System.EventHandler(this. Button1_Click);
private void Button1_Click(object sender, System.EventArgs e) // Button1_Click()方法
{
……
}
然而除了用户界面程序外,在很多其他地方也用到了事件驱动模式,比如观察者模式(Observer)或发布/订阅(Publish/Subscribe)里:在一个类里发布(Publish)某个可以被触发的事件,而其他的类就可以来订阅(Subscribe)该事件。一旦这个发布者类触发了该事件,那么运行时环境会立刻告知所有订阅了该事件的订阅者类:这个事件发生了!从而各个订阅者类可以作出它们自己的反应(调用相应方法)。
asp.net架构
一 asp.net请求的处理过程
-------------------
HttpModule 必须要掌握的东西
HttpHandler 必须要掌握的东西,非常有用
以上两个的实例
---------------------
asp.net 事件模型机制
-----------------------
一
客户的请求页面由aspnet_isapi.dll这个动态连接库来处理,把请求的aspx文件发送给CLR进行编译执行,然后把Html流返回给浏览器
--------------------------
二 页面事件
执行顺序
Page_Init:初始化值或连接
Page_Load:主要使用IsPostBack,该事件主要执行一系列得操作来首次创建asp.net页面或响应
由投递引起得客户端事件。在此事件之前,已还原页面和控件视图状态。
Page_DataBind:在页面级别上调用,也可在单个控件中调用。
DataBind_PreRender:数据绑定预呈现,恰好在保存视图状态和呈现控件之前激发此事件。
Page_Unload:此事件是执行最终清理工作的。
非确定事件
Page_Error:如果在页面处理过程中出现未处理的例外,则激发error事件。
Page_AbortTransaction:交易事件,事务处理中如果已终止交易,则激发此事件,购物车常用。
Page_CommitTransaction:如果已成功交易,则激发此事件。
--------------------------------------------------------
Global.asax中的事件(执行顺序)
Application_Start:应用程序启动时激发
Application_BeginRquest:http请求开始时激发
Application_AuthenticateRequest: 应用程序批准http请求时激发
Session_Start: 会话启动时激发
Application_EndRequest:Htttp请求结束时激发
Session_End:会话结束时激发
Application_End:应用程序结束时激发
Application_Error: 发生错误时激发
----------------------
ISAPI: 向web服务器插入某些组建,扩展功能,增强web服务器功能。
ISAPI: 扩展,win32的动态链接库,譬如aspnet_isapi.dll,可以把ISAPI扩展看作是一个普通的应用程序,它处理的目标是HTTP请求。
ISAPI: 过滤器,web服务器把请求传递给相关的过滤器,接下来过滤器可能修改请求,执行某些操作等等。
ASP.NET请求的处理过程:
基于管道模型,在模型中ASP.NET把http请求传递给管道中所有的模块。每个模块都接收HTTP请求,并有完全的控制权。一旦请求经过了所有的HTTP模块,最终被HTTP处理程序处理。HTTP处理程序对请求进行一些处理,并且结果将再次经过模块管道中的HTTP模块。
-----------
httpmodule
ISAPI过滤器(筛选器):IIS本身是不支持动态页面的,也就是说他仅仅支持静态HTML页面的内容,对于.asp .aspx .cgi .php等,IIS并不知道如果处理这些后缀标记,它就会把它当作文本,丝毫不做处理发送到客户端。为了解决这个问题,IIS有一种机制,叫做ISAPI的过滤器。它是一个COM组件。
ASP.NET服务在注册到IIS的时候,会把每个扩展可以处理的文件扩展名注册到IIS里面(如*.ascx *.aspx等)。扩展启动后,就根据定义好的方式来处理IIS所不能处理的文件,然后把控制权跳转到专门处理代码的进程中,asp.net中是aspnet_isapi.dll。让这个进程开始处理代码,生成标准的HTML代码,生成后把这些代码加入到原有的HTML中,最后把完整的HTML返回给IIS,IIS再把内容发送到客户端。
----------------
HttpModule
Http模块实现了过滤器(ISAPI filter)的功能,它是实现了System.Web.IHttpModule接口的.net组件。。这些组件通过在某些事件中注册自身,把自己插入到ASP.NET请求处理管道。当这些事件发生的时候,ASP.NET调用对请求有兴趣的HTTP模块,这样该模块就能处理请求了。有时候需要过虑一下http请求,注意它不是覆盖其他的包括系统自带的HttpModule,在Machine.config中配置完成。
--------------------------------------
HttpHandler
它实现了ISAPI Extention的功能,它处理请求(Request)的信息和发送响应(Response)。HttpHandler功能的通过必须实现IHttpHandler接口。HTTP处理程序是实现System.Web.IHttpHandler接口的.NET组件。任何实现了该接口的类都可以用于处理输入的Http请求。它就是Http处理程序。
在以前的ASP时候,当请求一个*.asp页面文件的时候,这个HTTP请求首先会被一个名为inetinfo.exe进程所截获,这个进程实际上就是www服务。截获之后它会将这个请求转交给asp.dll进程,这个进程就会解释这个asp页面,然后将解释后的数据流返回给客户端浏览器。其实ASP.DLL是一个依附在IIS的ISAPI文件,它负责了对诸如ASP文件,ASA等文件的解释执行,
-------------------------------------
ASP.NET的HTTP请求处理方法
当客户端向web服务器请求一个*.aspx的页面文件时,同asp类似,这个http请求也会被inetinfo.exe进程截获(www服务),它判断文件后缀之后,把这个请求转交给ASPNET_ISAPI.DLL而ASPNET_ISAPI.DLL则会通过一个Http PipeLine的管道,将这个http请求发送给ASPNET_WP.EXE进程,当这个HTTP请求进入ASPNET_WP.EXE进程之后,asp.net framework就会通过HttpRuntime来处理这个Http请求,处理完毕后将结果返回给客户端。
------------------------------------
当一个http请求被送入到HttpRuntime之后,这个Http请求会继续被送入到一个被称之为HttpApplication Factory的一个容器当中,而这个容器会给出一个HttpApplication实例来处理传递进来的http请求,而后这个Http请求会依次进入到如下几个容器中:
HttpModule --> HttpHandler Factory --> HttpHandler
当系统内部的HttpHandler的ProcessRequest方法处理完毕之后,整个Http Request就被处理完成了,客户端也就得到相应的东东了。
完整的http请求在asp.net framework中的处理流程:
HttpRequest-->inetinfo.exe->ASPNET_ISAPI.DLL-->Http Pipeline-->ASPNET_WP.EXE-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->HttpHandler-->HttpHandler.ProcessRequest()
如果想在中途截获一个httpRequest并做些自己的处理,就应该在HttpRuntime运行时内部来做到这一点,确切的说时在HttpModule这个容器中做到这个的。
----------------------------------------
-------------------------------------
系统本身的HttpModule实现一个IHttpModule的接口,当然我们自己的类也能够实现IHttpModule接口,这就可以替代系统的HttpModule对象了。
ASP.NET系统中默认的HttpModule:
DefaultAuthenticationModule 确保上下文中存在 Authentication 对象。无法继承此类。
FileAuthorizationModule 验证远程用户是否具有访问所请求文件的 NT 权限。无法继承此类。
FormsAuthenticationModule 启用 ASP.NET 应用程序以使用 Forms 身份验证。无法继承此类。
PassportAuthenticationModule 提供环绕 PassportAuthentication 服务的包装。无法继承此类。
SessionStateModule 为应用程序提供会话状态服务。
UrlAuthorizationModule 提供基于 URL 的授权服务以允许或拒绝对指定资源的访问。无法继承此类。
WindowsAuthenticationModule 启用 ASP.NET 应用程序以使用 Windows/IIS 身份验证。无法继承此类
--------------------------------------
这些系统默认的HttpModule是在文件machine.config中配置的,和我们开发时使用到的web.config的关系是:是在ASP.NET FRAMEWORK启动处理一个Http Request的时候,它会依次加载machine.config和请求页面所在目录的web.config文件,如果在machine中配置了一个自己的HttpModule,你仍然可以在所在页面的web.config文件中remove掉这个映射关系。
public class HelloWorldModule : IHttpModule
{
public HelloWorldModule()
{
}
public String ModuleName
{
get { return "HelloWorldModule"; }
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("
public void Dispose()
{
}
}
-----------------------------------------------------------------------------------
深入HttpModule
一个Http请求在被ASP.NET Framework捕获之后会依次交给HttpModule以及HttpHandler来处理。hm与hh之间不是完全独立的,实际上,http请求在hm传递的过程中会在某个事件内将控制权转交给hh的,而真正的处理在HttpHandler中执行完成后,HttpHandler会再次将控制权交还给HttpModule
上面的代码中的HttpModule的Init()中的参数是HttpApplication类型,它具有许多事件,包括BeginRequest,EndRequest,AuthentiacteRequest 等等。
-----------------------------------------------------------------
IHttpHandler
它是asp.net Framework提供的一个接口,定义了如果要实现一个Http请求的处理所需要必须实现的一些系统约定。也就是说,如果你想要自行处理某些类型的HTTP请求信息流的话,你需要实现这些系统约定才能做到。譬如一个*.aspx文件,用来处理此类型的Http请求,ASP.NET FRAMEWORK将会交给一个名为System.Web.UI.PageHandlerFactory的HttpHandler类来处理。
HH和HM一样,系统会在最初始由ASP.NET FRAMEWORK首先加载machine.config中的HttpHandler,而后会加载Web应用程序所在目录的web.config中的用户自定义的HttpHandler类。但是系统与我们自定义的HH之间的关系是"覆盖"的,也就是说如果我们自定义了一个针对"*.aspx"的HttpHandler类的话,那么系统会将对此http请求的处理权完全交给我们自己定义的这个HttpHandler类来处理,而我们自己的HttpHandler类则需要自己完全解析这个Http请求,并作出处理。
IHttpHandler接口中最重要的方法ProcessRequest,这个方法就是HttpHandler用来处理一个Http请求,当一个Http请求经过由HttpModule容器传递到HttpHandler容器中的时候,framework会调用HttpHandler的ProcessRequest方法来做对这个Http请求做真正的处理。
framework实际上并不是直接把相关页面的HTTP请求定位到一个内部默认的IHttpHandler容器之上的,而是定位到了其 内部默认的IHttpHandler Factory上了。IHttpHandler Factory的作用就是对很多系统已经实现了的IHttpHandler容器进行调度和管理的,这样做的优点是大大增强了系统的负荷性,提升了效率。
HttpHandler是一个HTTP请求的真正处理中心,也正是在这个HttpHandler容器中,ASP.NET Framework才真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。
IHttpHandler是什么
IHttpHandler定义了如果要实现一个HTTP请求的处理所必需实现的一些系统约定。HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。
IHttpHandler如何处理HTTP请求
当一个HTTP请求经同HttpModule容器传递到HttpHandler容器中时,ASP.NET Framework会调用HttpHandler的ProcessRequest成员方法来对这个HTTP请求进行真正的处理。以一个ASPX页面为例,正是在这里一个ASPX页面才被系统处理解析,并将处理完成的结果继续经由HttpModule传递下去,直至到达客户端。
对于ASPX页面,ASP.NET Framework在默认情况下是交给System.Web.UI.PageHandlerFactory这个HttpHandlerFactory来处理的。所谓一个HttpHandlerFactory,所谓一个HttpHandlerFactory,是指当一个HTTP请求到达这个HttpHandler Factory时,HttpHandlerFactory会提供出一个HttpHandler容器,交由这个HttpHandler容器来处理这个HTTP请求。
一个HTTP请求都是最终交给一个HttpHandler容器中的ProcessRequest方法来处理的。
图1:ProcessRequest方法
一个简单的HttpHandler容器
通过实现IHttpHandler接口可以创建自定义HTTP处理程序,该接口只包含两个方法。通过调用IsReusable,IHttpHandlerFactory可以查询处理程序以确定是否可以使用同一实例为多个请求提供服务。ProcessRequest方法将HttpContext实例用作参数,这使它能够访问Request和Response内部对象。在一个HttpHandler容器中如果需要访问Session,必须实现IRequiresSessionState接口,这只是一个标记接口,没有任何方法。
示例1:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.SessionState;
namespace MyHandler
{
///
/// 目的:实现一个简单的自定义HttpHandler容器
/// 作者:文野
/// 联系:[email protected]
///
public class MyFirstHandler : IHttpHandler,IRequiresSessionState
{
#region IHttpHandler 成员
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("Hello HttpHandler
");
context.Session["Test"] = "测试HttpHandler容器中调用Session";
context.Response.Write(context.Session["Test"]);
}
#endregion
}
}
在Web.config中加入如下配置:
<httpHandlers>
<add verb="*" path="*" type="MyHandler.MyFirstHandler, MyHandler"/>
httpHandlers>
IHttpHandler工厂
ASP.NET Framework实际不直接将相关的页面资源HTTP请求定位到一个其内部默认的IHttpHandler容器之上,而定位到了其内部默认的IHttpHandler工厂上。IHttpHandler工厂的作用是对IHttpHandler容器进行调度和管理。
IHttpHandlerFactory接口包含两个方法。GetHandler返回实现IHttpHandler接口的类的实例,ReleaseHandler使工厂可以重用现有的处理程序实例。
示例2:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace MyHandler
{
public class MyHandlerFactory : IHttpHandlerFactory
{
#region IHttpHandlerFactory 成员
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
string fname = url.Substring(url.IndexOf('/') + 1);
while (fname.IndexOf('/') != -1)
fname = fname.Substring(fname.IndexOf('/') + 1);
string cname = fname.Substring(0, fname.IndexOf('.'));
string className = "MyHandler." + cname;
object h = null;
try
{
// 采用动态反射机制创建相应的IHttpHandler实现类。
h = Activator.CreateInstance(Type.GetType(className));
}
catch (Exception e)
{
throw new HttpException("工厂不能为类型"+cname+"创建实例。",e);
}
return (IHttpHandler)h;
}
public void ReleaseHandler(IHttpHandler handler)
{
}
#endregion
}
public class Handler1 : IHttpHandler
{
#region IHttpHandler 成员
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("来自Handler1的信息。");
}
#endregion
}
public class Handler2 : IHttpHandler
{
#region IHttpHandler 成员
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.Write("来自Handler2的信息。");
}
#endregion
}
}
转载
Sharpmap 作为优秀的基于vs2005的GIS解决方案,大家也对其了解甚多,我就不多说了。在实际使用中,特别是web控件,作者并没有暴露很多编程方法,本文基于此进行讨论。
在项目开发中,我们希望在鼠标拖拽时起码要实现几个功能:平移、拉框缩放、拉框选择。通过更改Sharpmap.UI.dll的方式修改,可以实现。
首先,增加鼠标拖拽选择模式属性MouseMode,并增加enum,代码形如:
public enum eMouseMode
{
Pan,
Zoom,
Select
}
private eMouseMode _MouseMode;
/**
/// Set Mouse down,up, move event to pan or zoom mode
///
[Category("Behavior")]
[DefaultValue(0)]
[Description("设置鼠标拖拽方式:即设置Mousedown,Mousemove,Mouseup事件的处理方式。默认值为Pan。")]
public eMouseMode MouseMode
{
get { return _MouseMode; }
set { _MouseMode = value; }
}
其次,将属性暴露给JS,让客户端可以调用。
通过修改GenerateClientScripts函数,增加setvarsScript变量定义。
拉框需要有html控件,我这里使用div。
首先,在GenerateMapBox函数中生成控件,使用Controls.add方法增加进来。
其次,在JS中注册。
通过修改JS文件的SharpMap_Init函数和CS文件的GenerateClientScripts函数,将增加的控件暴露给JS使用。
至此我们在前后台均可以使用新增加的控件和方法。然后,就可以在SharpMap_MouseDown(Up, Over)函数里面写代码了。
SharpMap 深度分析之数据源
■ 文/Mars
在《3s 新闻周刊》的第一期对SharpMap 源码做了一个走马观花式的分析,没有深入一
些细节性的东西,本文则就数据源的问题作一些深入分析。
在SharpMap 中,数据的获取使用了数据Provider。Provider 或者Provider 模式对于很多
人应该都不陌生,在DNN 和Asp.net 2.0 中都大量应用了Provider 模式。目前主流的GIS 平
台的数据提供也应该基本上都是基于Provider 这样的模式,大家比较熟悉的应该是SuperMap
提出的多源空间数据引擎的概念。
在SharpMap 里,数据Provider 是这样使用的:
string ConnStr =
"Server=127.0.0.1;Port=5432;UserId=postgres;Password=password;Database=my
GisDb;";
myLayer.DataSource = new SharpMap.Providers.PostGIS(ConnStr, "myTable",
"the_geom", 32632);
而实际上,在Layer 类里,DataSource 定义为:
public SharpMap.Data.Providers.IProvider DataSource
{
...
}
也就是说,这里的Provider 是针对IProvider 接口编程的,这样,对于不同的层,你可
以指定不同的数据源(通过使用不同的数据Provider,而支持不同的数据格式)。下面是
Provider 接口的类图,定义了接口的属性和操作:
个人认为,Provider 的核心思想在于面向接口编程,也就是说通过接口定义需要的服务,
至于服务的实现,可以通过具体的方式来实现。就GIS 数据引擎来说,就是定义对空间数
据需要的操作,例如打开、关闭、读取某个范围内的数据,以及数据的检索、分析等等接口,
然后通过实现该接口来实现对不同格式数据的支持。例如对Shape 文件的操作和对PostGIS
文件的操作是完全不同的,但各自的Provider 都实现了IProvider 接口。在SharpMap 系统内
部,对数据的操作,例如放大缩小、变换、显示,只需要针对接口(IProvider)编程,而无
须关心数据的具体格式,而实现对不同格式数据源的支持。其结构大概如下图所示。
熟悉SuperMap 的朋友可以发现这个结构和超图的多源空间数据引擎的概念如出一辙。
这里的空间数据Provider 实现和ASP.net 中的DNN 等的Provider 模式的不同在于,DNN
是通过配置文件和反射机制,来实现不同的Provider 的更换,而无须更改代码实现(客户代
码),而SharpMap 或其他GIS 的类似实现是需要在开发时指定使用的Provider。前者的好处
在于使用系统的客户代码在编译部署以后,也可以动态更换,增加新的数据引擎。
Provider 的实现还有一个比较重要的问题就是要操作的数据的定义,也就是系统内部的
空间数据格式的问题。因为具体的Provider 的实现最终要将数据转换为系统内部的数据类型
和结构,然后返回。
对于具体的Geometry 的结构,SharpMap 是在OGC 的规范的基础上实现的。对于这部
分内容,很多面向对象的书也喜欢用空间几何对象、圆、正方形、线段等等来讲述类、对象、
继承等概念,大家都很熟悉,这里就不多说了。对OGC 的Simple Feature 实现比较好的一
个.net 类库是NTS(JTS 的.net 移植版本),目前正在看他的源码,后面会写一些自己的笔记。
SharpMap 的一些代码,从其注释来看也是在NTS 的基础上实现的。
SharpMap 的Provider 没有定义数据的修改、编辑,从理论上讲,完全可以实现任意数
据的读取、修改,但实际上,数据的读取显示一般来说实现难度不是很大,因为空间对象不
外乎点、线、面及其组合这样的对象;但由于内部数据结构、拓扑关系、索引等问题,修改、
编辑就比较困难了。例如SuperMap 的产品也只是可以只读读取一些其他格式的数据(如
MicroStation DGN,AutoCAD 数据),而没有修改功能。