gisempire100
捉鬼专家
捉鬼专家
  • 注册日期2004-08-13
  • 发帖数552
  • QQ
  • 铜币2462枚
  • 威望0点
  • 贡献值0点
  • 银元0个
阅读:1682回复:0

ArcGis Server ADF Toolbar与Map的客户端和服务端交互过程分析

楼主#
更多 发布于:2009-10-16 09:37
<P><STRONG>1、Toolbar的初始化步骤</STRONG></P>
<P>   [1]、Toolbar.FrameworkInitialize()<BR>          <BR>          在这里建立所有的Tool实例(但是未初始化完其所有属性)。<BR>          <BR>   [2]、Toolbar.OnLoad()<BR>          <BR>          在这里主要是调用了AddToolItems()方法建立Map里边的工具实例。Toolbar的工<BR>          具类名是ToolbarItem,而Map里边的工具类名是MapToolItem,两者并不一样。<BR>          <BR>          AddToolItems()具体工作:<BR>          <BR>          (1)、取出Toolbar的所有ToolbarItem(s)<BR>          (2)、foreach(循环)<BR>             {<BR>                1、调用callToolbarItemInitialize()对ToolbarItem进行进一步的初始化,<BR>                而callToolbarItemInitialize()内部又调用LoadClassFromAssembly(),其<BR>                实就是建立起ToolBarItem的ServerActionClass的实例,这个实例通过一<BR>                个Hashtable保存,让ToolbarItem名称和Object配对。<BR>                  <BR>                2、以ToolbarItem为原型,建立MapToolItem实例,并添加到Map的内部工<BR>                具集中。<BR>                  <BR>                  MapToolItem有一个属性ServerToolAction,用来保存该Item对应的<BR>                  ServerActionClass的实例。<BR>             }<BR>             <BR>    [3]、ToolbarBase.RenderContents() -> RenderRuntime()<BR>    <BR>         这个步骤主要用来生成工具条及工具按钮的Client HTML代码<BR>    <BR>             RenderRuntime()<BR>             { <BR>                ......            <BR>                <BR>                //<BR>                // 调用ToolbarItem的Render()方法,让每一个ToolBarItem都产生自己<BR>                // 对应的方法<BR>                //<BR>                foreach (ToolbarItem item in this.ToolbarItems)<BR>                {<BR>                    item.Render(this, num2, num3, false, builder);<BR>                }<BR>                ...<BR>             }<BR>            <BR>        Tool.Redner()里边有很多工作,但是最关键的是以下几行代码:<BR>        <BR>            Render()<BR>            {<BR>                ... <BR>                if (!inDesignMode ;; !base.Disabled)<BR>                {<BR>                    builder.Append(string.Format("  onMouseDown=\"ToolbarMouseDown( '{0}', '{1}', 'Tool', event);\"\n", toolbar.ClientID, this.Name));<BR>                    builder.Append(string.Format("  onMouseOver=\"ToolbarMouseOver('{0}', '{1}');\"\n", toolbar.ClientID, this.Name));<BR>                    builder.Append(string.Format("  onMouseOut=\"ToolbarMouseOut( '{0}', '{1}');\"\n", toolbar.ClientID, this.Name));<BR>                }<BR>                ...<BR>            }   <BR>            <BR>        这个代码的意思就是说,如果用户单击了工具条上的按钮,就执行Javascript的<BR>        函数ToolbarMouseDown()等。<BR>        <BR>        这个ToolbarMouseDown()出现在ESRI.ADF.UI.Toolbar.js里边。<BR>            <BR>            <BR><STRONG>2、客户端如何发送信息到服务端?</STRONG></P>
<P>    当我们单击工具条上的一个按钮时,根据上面的分析,ToolbarMouseDown()被执行。<BR>    <BR>    我们来看看ToolbarMouseDown()具体干啥:<BR>    <BR>        function ToolbarMouseDown(toolbarName, toolbarItemName, buttonType, e)<BR>        {<BR>            .......                    <BR>         if (buttonType == "Tool") {<BR>             ......<BR>          var clientAction =  toolbar.items[toolbarItemName].clientAction;<BR>          if (clientAction != null) <BR>          {<BR>           var clientActions = "";<BR>              if (!toolbar.items[toolbarItemName].isClientActionCustom) <BR>              {<BR>            var buddies = toolbar.buddyControls;<BR>            if (buddies != null) {<BR>             for (var i = 0; i < buddies.length; i++)<BR>             {<BR>              var modeField = f.elements[buddies + "_mode"];<BR>              if (modeField != null)<BR>               modeField.value = toolbarItemName;<BR>              var cursor = toolbar.items[toolbarItemName].cursor;<BR>              if (cursor != null)<BR>               clientActions = clientActions + clientAction + " ( '" + buddies + "' , '" + toolbarItemName + "', " + toolbar.items[toolbarItemName].showLoading + ",'" + cursor + "'); ";<BR>              else<BR>               clientActions = clientActions + clientAction + " ( '" + buddies + "' , '" + toolbarItemName + "', " + toolbar.items[toolbarItemName].showLoading + "); ";<BR>             }<BR>            }<BR>           }<BR>           else<BR>           {<BR>            clientActions = clientAction;<BR>           }<BR>           <BR>           ...<BR>           if (toolbar.items[toolbarItemName].preExecFunction != null)<BR>            clientActions += toolbar.items[toolbarItemName].preExecFunction;<BR>            <BR>                                // 调用ClientAction<BR>           var clientActionFunction = new Function(clientActions);<BR>           clientActionFunction.call(null);<BR>           <BR>           //select this tool and unselect others<BR>           Toolbars[toolbarName].selectTool();<BR>           Toolbars[toolbarName].refreshGroup();<BR>          }<BR>         }<BR>         ....<BR>        }<BR>                <BR>     这段代码的简单意思就是说,如果ClientAction是我们自定义的,则直接执行。如果<BR>     不是呢,则构造如下形式的调用:<BR>         <BR>          Function.Call("Map[XXX]('Map1','[ToolName]',showLoading,cursor");<BR>     <BR>     MapXxx(..)其实是Map内部提供的JS函数(ESRI.ADF.UI.Map.js里边),总共有如下类型:<BR>     <BR>     MapDragImage = ESRI.ADF.MapTools.MapDragImage = function(mapid, mode, showLoading, cursor); <BR>     MapDragRectangle = ESRI.ADF.MapTools.DragRectangle = function(mapid, mode, showLoading, cursor) ;<BR>     MapBox = MapDragBox = ESRI.ADF.MapTools.DragRectangle;<BR>     MapPoint = ESRI.ADF.MapTools.Point = function(mapid, mode, showLoading, cursor) ;<BR>     MapLine = ESRI.ADF.MapTools.Line = function(mapid, mode, showLoading, cursor, vectorToolbarState) ;<BR>     MapPolyline = ESRI.ADF.MapTools.Polyline = function(mapid, mode, showLoading, cursor, vectorToolbarState) ;<BR>     MapPolygon = ESRI.ADF.MapTools.Polygon = function(mapid, mode, showLoading, cursor, vectorToolbarState) ;<BR>     MapDragCircle = MapCircle = ESRI.ADF.MapTools.Circle = function(mapid, mode, showLoading, cursor, vectorToolbarState) ;<BR>     MapDragOval = MapOval = ESRI.ADF.MapTools.Oval = function(mapid, mode, showLoading, cursor, vectorToolbarState) ;<BR>     <BR>     现在我们以MapDragRectangle()为来自来分析:<BR>     <BR>        MapDragRectangle = ESRI.ADF.MapTools.DragRectangle = function(mapid, mode, showLoading, cursor) <BR>        {<BR>         var map = $find(mapid);<BR>         if(!map) { map=Pages[mapid]; }<BR>         if(ESRI.ADF.UI.Map.isInstanceOfType(map)) <BR>         {<BR>          if(mode==='MapZoomIn') <BR>          {<BR>           map.set_mouseMode(ESRI.ADF.UI.MouseMode.ZoomIn);<BR>          }<BR>          else if(mode==='MapZoomOut') <BR>          {<BR>           map.set_mouseMode(ESRI.ADF.UI.MouseMode.ZoomOut);<BR>          }<BR>          else <BR>          {<BR>           var onComplete = Function.createDelegate(map, function(geom) {<BR>            var geomString = geom.get_xmin()+':'+geom.get_ymin()+'|'+geom.get_xmax()+':'+geom.get_ymax();<BR>            this.doCallback('EventArg=DragRectangle;coords='+geomString+';'+mapid+'_mode='+mode,this);  <BR>           });<BR>           <BR>           map.getGeometry(ESRI.ADF.Graphics.ShapeType.Envelope,onComplete,function(){map.__activeToolMode=null;},ESRI.ADF.MapTools.lineColor,ESRI.ADF.MapTools.fillColor,cursor, true);<BR>           map.__activeToolMode = mode;<BR>          }<BR>          ..<BR>          }<BR>         }<BR>         ...<BR>        };<BR>        <BR>    当Tool Name是MapZoomIn和MapZoomOut时,Map内部提供支持。否则就执行一些操作之<BR>    后,然后把操作信息通过doCallback()发送到Server端。所谓执行一些操作,实际上<BR>    就是画图,通过调用map.getGeometry(...,onComplete,...)来执行,当执行完成之后,<BR>    onComplete被执行。<BR>    <BR>  var onComplete = Function.createDelegate(map, function(geom) <BR>  {<BR>   var geomString = geom.get_xmin()+':'+geom.get_ymin()+'|'+geom.get_xmax()+':'+geom.get_ymax();<BR>   this.doCallback('EventArg=DragRectangle;coords='+geomString+';'+mapid+'_mode='+mode,this);  <BR>  });<BR>  <BR>    执行操作完成之后,map会构造图形的geom实例,并作为onComplete()的参数。通过上<BR>    面的代码我们状况,这个时候只是简单执行map.doCallback()把信息发送回到Server。<BR>     <BR>    map.doCallback()用到一个重要的内部变量callbackFunctionString,这个变量的值由<BR>    Server端ESRI.ArcGIS.ADF.Web.UI.WebControls.WebControl控件生成,看看它的生成代码:<BR>      <BR>        protected internal virtual string CallbackFunctionString<BR>        {<BR>            get<BR>            {<BR>                if (this.RequiresPartialPostback)<BR>                {<BR>                    this.callbackFunctionString = string.Format("__esriDoPostBack('{0}','{1}', argument, ESRI.ADF.System.ProcessMSAjaxCallbackResult, context)", this.UniqueID, this.ClientID);<BR>                }<BR>                else<BR>                {<BR>                    //生成语句:WebForm_DoCallback('__Page',argument,ESRI.ADF.System.processCallbackResult,context,postBackError,true);<BR>                    <BR>                    this.callbackFunctionString = this.Page.ClientScript.GetCallbackEventReference(this, "argument", "ESRI.ADF.System.processCallbackResult", "context", "postBackError", true);<BR>                    </P>
<P>                }</P>
<P>                return this.callbackFunctionString;<BR>            }<BR>        }<BR>        <BR>     RequiresPartialPostback在什么情况为TRUE呢?就是当你的Page中存在一个<BR>     ScriptManager时,这个值为TRUE,执行部分Postback。如果没有ScriptManager,<BR>     将执行Callback。通过上面代码我知道,如果是postback,则执行:<BR>          __<BR>          __esriDoPostBack(this.UniqueID,this.ClientID, argument, ESRI.ADF.System.ProcessMSAjaxCallbackResult, context)<BR>          <BR>     如果是callback,则执行:     </P>
<P>            WebForm_DoCallback('__Page',argument,ESRI.ADF.System.processCallbackResult,context,postBackError,true);            <BR>     <BR>     不管是Postback还是Callback,信息发送到服务端之后,将由服务端进行处理,然后<BR>     再回传信息到客户端,由CallbackFunctionString里边定义的JS函数处理.如果是postback,<BR>     则由ESRI.ADF.System.ProcessMSAjaxCallbackResult()处理,否则由ESRI.ADF.System.processCallbackResult()处理。<BR>        <BR><STRONG>3、服务端如何处理信息?</STRONG>         </P>
<P>   当信息达到Server端之后,系统通过调用RaiseCallbackEvent(arg)或者RaisePostbackEvent(arg)<BR>   把参数传递到Map内部。然后系统调用Map.GetCallackResult()取得Map要传回给客户端的信息。<BR>   <BR>   Map.GetCallbackResult()的大概执行步骤:<BR>   <BR>   [1]、通过当前的Tool Item得到对应的ServerActionClass的实例。这个实例是在<BR>        callToolbarItemInitialize()被建立的,具体看前面的分析。<BR>   <BR>   [2]、先把参数拆分成Name/Value值对,然后调用handlePostBack()对“EventArg”的参<BR>        数进行处理,<BR>       <BR>       handlePostback()<BR>       {<BR>          ....<BR>          if(这是一个选择矩形操作?)<BR>          {<BR>                ....<BR>                Point[] pointArray = Utility.ConvertVectorStringToDoublePointArray(str);<BR>                args = new MapRectangleEventArgs(this, str2, new Envelope(pointArray[0], pointArray[1]));<BR>                serverToolAction.ServerAction(args);<BR>                ...<BR>          }<BR>          ....<BR>       }<BR>       <BR>       在这一步,我们自己定义的IMapServerToolAction.ServerAction()终于被执行了。</P>
<P>   [3]、 最后通过代码以下代码把信息返回给客户端。</P>
<P>           return this.CallbackResults.ToString();<BR>           <BR>        注意这个CallbackResults,它是CallbackResultCollection,里边可以添加不同<BR>        的CallbackResult,比如我们也可以在我们的ServerAction()里边添加我们自己<BR>        的CallbackResult到里边,让Map统一返回。<BR>        <BR>        CallbackResult类构造函数如下:<BR>        <BR>            public CallbackResult( string controlType,string controlID,string eventArg,params object[] parameters)<BR>        <BR>        其中,eventArg只能是content, innercontent, image, or javascript(还有set、invoke)。<BR>        如果是javascript,则前面两个参数没有作用,否则必须填写。有关部门CallbackResult<BR>        的具体使用可以参照其它例子。<BR>         <BR><STRONG>4、客户端如何处理服务端返回的信息?</STRONG></P>
<P>   服务端返回的信息由</P>
<P>       ESRI.ADF.System.processCallbackResult()</P>
<P>   进行处理,具体可以看ESRI.ADF.System.debug.js的代码。<BR>   <BR><STRONG>5、扩展</STRONG></P>
<P>   从上面看到,释放鼠标导致画图操作完成之后,map就发出callback了,如果我们想再执<BR>   行一些操作再发回怎么办?可以自己定义ClientAction来达到这个目的,如设置ClientAction<BR>   成“MyDragRectangle()“,<BR>   <BR>   function MyDragRectangle_Simple()<BR>   {<BR>        alert("selct rectangle now..");<BR>        <BR>        //<BR>        // 第二个参数,是Tool Name,如果是MapZoomIn或者MapZoomOut,则<BR>        // 将由Map内置的功能处理。<BR>        // <BR>        // 为了定义自己的选择操作,必须使用其它名字。<BR>        //<BR>        MapDragRectangle('Map1','Select',false,'hand');<BR>    }<BR>   <BR>   function MyDragRectangle_Adv()<BR>   {<BR>     var map = $find(mapid);</P>
<P>     if(ESRI.ADF.UI.Map.isInstanceOfType(map))<BR>     {<BR>     var onComplete = Function.createDelegate(map, function(geom) <BR>            {<BR>  var geomString = geom.get_xmin()+':'+geom.get_ymin()+'|'+geom.get_xmax()+':'+geom.get_ymax();<BR>   <BR>                //........干我们自己的活..(比如添加图形到Map上,不让它消失等)<BR>   <BR>  this.doCallback('EventArg=DragRectangle;coords='+geomString+';'+mapid+'_mode='+mode,this);  <BR>     });<BR>   <BR>            map.getGeometry(ESRI.ADF.Graphics.ShapeType.Envelope,onComplete,function(){map.__activeToolMode=null;},ESRI.ADF.MapTools.lineColor,ESRI.ADF.MapTools.fillColor,cursor, true);<BR>            map.__activeToolMode = mode;<BR>        }       <BR>   }<BR>        <BR></P>
喜欢0 评分0
A friend is never known till a man has need. ...CL
游客

返回顶部