前面的開發(fā)系列均是使用server開發(fā)模板程序Web Mapping Application,工具條上的基本工具是已經(jīng)在模板中定制好的,在實際項目應(yīng)用中,我們需要的工具遠(yuǎn)遠(yuǎn)不僅如此,如何在工具條中增加新的自定義工具是開發(fā)系列(五)所要描述的,其中使用ASP.Net 2.0 Callback framework進(jìn)行異步刷新地圖是重點。
目標(biāo):
自定義工具按鈕進(jìn)行矩選查詢,高亮顯示所選擇的地圖要素,頁面下方的Gridview顯示所選擇要素的屬性信息。
準(zhǔn)備工作:
1.了解ESRI.ArcGIS.Server.WebControls.IMapServerToolAction接口
2.了解ASP.Net 2.0 Callback framework
3.新建一個網(wǎng)站,在ArcGIS Web Controls控件中拖動如下控件:Toolbar、Map、Toc、MapResourceManager,以及常用控件Label、DropDownList、Gridview。
4.設(shè)置控件屬性,Toolbar、Toc的BuddyControls均為Map1,Toolbar的BuddyControlType為Map,Map控件的MapResourceManager為MapResourceManager1。
5.更改MapResourceManager屬性,添加兩個Resource:Selection和NorthAmerica,類型分別是Graphics Layer和ArcGIS Server Internet。
最后視圖效果:
思路:
現(xiàn)在重新想想我們要做什么,首先要自定義一個工具按鈕,使用該工具后在地圖上進(jìn)行矩形選擇,對選擇的要素高亮顯示,同時gridview顯示出這些要素的屬性信息。整個過程看似容易,實際上需要在客戶端和服務(wù)器端之間來回切換,異步調(diào)用,這里用到了ASP.Net Callback framework,其實Server中很多地圖操作都基于asp.net callback,或是實現(xiàn)了ICallbackEventHandler接口,理解了這一段程序開發(fā)有利于深入了解Server地圖刷新、Task等組件的工作機(jī)制。
首先在Toolbar上新增一個按鈕Select Features,上圖其實已經(jīng)加入了,加入的方法是,選擇Toolbar控件屬性ToobarItems,添加一個Tool,設(shè)置以下值:
Text:Select Feature
CientAction
ragRectangle
Name:SelectTool
ServerActionAssembly:App_Code
ServerActionClass:SelectFeatures
OK,搞定!
除了上述屬性外,還可以設(shè)置該按鈕各種狀態(tài)下的圖片顯示、ToolTip等等,這里就省了,縱觀這些屬性,可以看出既有js腳本的交互(已經(jīng)封裝了,通過 ToolEventArgs傳入),也有服務(wù)器端功能的實現(xiàn),這時我們需新建一個類SelectFeatures,并實現(xiàn) IMapServerToolAction接口,類中實現(xiàn)IMapServerToolAction的方法ServerAction。
public
class SelectFeatures : IMapServerToolAction {
public
void ServerAction(ToolEventArgs args)
} 代碼實現(xiàn):
1.獲取矩形框的屏幕坐標(biāo)
要查詢矩選的地圖信息,首先應(yīng)知道矩形的坐標(biāo),在服務(wù)器端如何獲取呢?
Map mapctrl = null;
mapctrl = (Map)args.Control;
// 獲取下拉框中的數(shù)據(jù),在后面實現(xiàn)
string targetlayername = (string)mapctrl.Page.Session["TargetLayer"];
RectangleEventArgs rectargs = null;
// 強(qiáng)制類型轉(zhuǎn)換為RectangleEventArgs
rectargs = (RectangleEventArgs)args;
// 獲取矩形選擇框的屏幕坐標(biāo)
System.Drawing.Rectangle rect = rectargs.ScreenExtent;
ESRI.ArcGIS.ADF.Web.Geometry.Point minpnt = ESRI.ArcGIS.ADF.Web.Geometry.Point.ToMapPoint(rect.Left, rect.Bottom, mapctrl.Extent, (int)mapctrl.Width.Value, (int)mapctrl.Height.Value);
ESRI.ArcGIS.ADF.Web.Geometry.Point maxpnt = ESRI.ArcGIS.ADF.Web.Geometry.Point.ToMapPoint(rect.Right, rect.Top, mapctrl.Extent, (int)mapctrl.Width.Value, (int)mapctrl.Height.Value);
ESRI.ArcGIS.ADF.Web.Geometry.Envelope mappoly = null;
// minpnt、maxpnt分別是左下、右上坐標(biāo)點
mappoly = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(minpnt, maxpnt); 所有的信息都是通過args獲取,它是一個ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs對象,包含了客戶端Map控件和當(dāng)前客戶端工具的信息,RectangleEventArgs是它的子類,強(qiáng)制性轉(zhuǎn)換后得到矩選的矩形坐標(biāo),最后得到一個 Envelope,用于spatialfilter.Geometry屬性。
2.查詢所選擇的要素并對Graphics Layer進(jìn)行渲染實現(xiàn)高亮
這部分內(nèi)容完全可以參考《
ArcGIS Server 開發(fā)系列(三)--漫游 Graphics data sources》,只需要注釋掉WhereClause屬性賦值,再增加一行代碼:
ESRI.ArcGIS.ADF.Web.SpatialFilter spatialfilter = new ESRI.ArcGIS.ADF.Web.SpatialFilter();
spatialfilter.ReturnADFGeometries = false;
spatialfilter.MaxRecords = 1000;
//spatialfilter.WhereClause = txtQuery.Text;
spatialfilter.Geometry = mappoly; 3.異步刷新Gridview顯示地圖要素的屬性
GridView gdview = (GridView)mapctrl.Page.FindControl("GridView1");
object[] oa = new
object[1];
string showtable = "'visible'";
// datatable為矩選時所選擇的地圖要素,綁定到gridview
gdview.DataSource = datatable;
gdview.DataBind();
string returnstring = null;
using (System.IO.StringWriter sw = new System.IO.StringWriter())
{
HtmlTextWriter htw = new HtmlTextWriter(sw);
gdview.RenderControl(htw);
htw.Flush();
returnstring = sw.ToString();
}
// innercontent相當(dāng)于innerhtml
CallbackResult cr = new CallbackResult("div", "griddiv", "innercontent", returnstring);
// 通過回調(diào)將信息從服務(wù)器端傳輸?shù)娇蛻舳?/font>
mapctrl.CallbackResults.Add(cr);
if (datatable.Rows.Count > 1)
{
showtable = "'visible'";
}
else
{
showtable = "'hidden'";
}
string sa = "var griddiv = document.getElementById('griddiv');";
sa += "griddiv.style.visibility = "
+ showtable +
";";
oa[0] = sa;
CallbackResult cr1 = new CallbackResult(null, null, "javascript", oa);
mapctrl.CallbackResults.Add(cr1);
這段代碼最關(guān)鍵的類是CallbackResult,它簡化了web adf framework中客戶端回調(diào)的處理,不用再創(chuàng)建自己的客戶端和服務(wù)器端邏輯,使用CallbackResult就可以將信息傳回客戶端,更新客戶端頁面的內(nèi)容、圖片或執(zhí)行js腳本。關(guān)于CallbackResult構(gòu)造方法第三個參數(shù),下面js代碼寫的很詳細(xì):
if (action=="content") {
o = document.getElementById(actions[1]);
if (o != null)
{
o.outerHTML=actions[3];
}
}
else
if (action=="innercontent") {
o = document.getElementById(actions[1]);
if (o != null)
{
o.innerHTML=actions[3];
}
}
else
if (action=="image")
{
o = document.images[actions[1]];
if (o != null)
{
o.src = actions[3];
}
else alert (actions[1] +
" was null");
}
else
if (action=="javascript") {
eval(actions[3]);
}
4.填充DropDownList
DropDownList顯示的是ArcGIS Server Internet地圖數(shù)據(jù)源所包含的圖層名稱,選擇哪個圖層,矩選時就對哪個圖層進(jìn)行查詢,DropDownList的填充在Page_PreRender過程中。
if (!IsPostBack)
{
ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality mf = (ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality)Map1.GetFunctionality(1);
ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisresource = mf.Resource;
bool supported = gisresource.SupportsFunctionality(typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality));
if (supported)
{
ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality qfunc = (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)gisresource.CreateFunctionality(typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null);
string[] lids;
string[] lnames;
qfunc.GetQueryableLayers(null, out lids, out lnames);
for (int i =
0; i < lnames.Length; i++)
{
LayerDropDownList1.Items.Add(lnames);
}
Session["TargetLayer"] = LayerDropDownList1.Items[0].Value;
}
}
5.實現(xiàn)ICallbackEventHandler接口
Default.aspx.cs的_Default實現(xiàn)ICallbackEventHandler接口,在類中實現(xiàn)RaiseCallbackEvent和GetCallbackResult兩個方法,做ASP.Net 2.0的對ICallbackEventHandler應(yīng)該是再熟悉不過了
但下來框顯示圖層為什么要用到callback?
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Session["TargetLayer"] = "";
}
LayerDropDownList1.Attributes.Add("onchange", "ChangeLayer()");
sADFCallBackFunctionInvocation = Page.ClientScript.GetCallbackEventReference(this, "message", "processCallbackResult", "context", "postBackError", true);
}
public void ChangeDropDownListServer(string ea)
{
char[] parser_char = { ',' };
string[] messages = ea.Split(parser_char);
string dll1 = messages[1];
Session["TargetLayer"] = dll1;
}
ICallbackEventHandler 成員#region ICallbackEventHandler 成員
public void RaiseCallbackEvent(string eventArgument)
{
if (eventArgument.Contains("ddl1"))
{
ChangeDropDownListServer(eventArgument);
}
}
public
string GetCallbackResult()
{
return returnstring;
}
原因就在這里,改變Session ["TargetLayer"]的值,SelectFeatures需要知道是對哪個圖層進(jìn)行查詢的,從而對在那個圖層選擇要素進(jìn)行高亮及屬性顯示,這里 callback僅僅是在做了變量值的處理。最后在頁面之間加入js腳本ChangeLayer()。
<script type="text/javascript" language="javascript">
var context;
function ChangeLayer()
{
var message;
var ddl1value = document.getElementById('LayerDropDownList1').value;
message = 'ddl1';
message += ',' + ddl1value;
<%=sADFCallBackFunctionInvocation%>
}
</script>
運(yùn)行程序:
其中黃色區(qū)域就是Select Features按鈕矩選的要素,下方gridview顯示了查詢到的屬性結(jié)果。
程序中有兩個地方用到了異步刷新,一個是ASP.Net 2.0原有接口ICallbackEventHandler,另一個是Web ADF framework的CallbackResult類,最初認(rèn)為簡單異步刷新用自己寫的XMLHttpRequest請求更為簡單,如上例中對 session存儲值的改變,不用ICallbackEventHandler,但是在server地圖互操作的過程中, ICallbackEventHandler給我們提供了更多的便利。
繼續(xù)思考:
1.本例實現(xiàn)了根據(jù)地圖查詢屬性,反過來根據(jù)屬性查詢幾何圖形怎么實現(xiàn)呢?其實前面《ArcGIS Server 開發(fā)系列(三)--漫游 Graphics data sources》已經(jīng)講到了,只不過需要將條件查詢的信息,更改為在gridview或其他地方選擇的屬性信息,然后高亮顯示相應(yīng)的幾何要素。
2.這種幾何要素圖形和屬性信息的關(guān)聯(lián)可以應(yīng)用于各種不同的業(yè)務(wù)需求中,如圖形和屬性的同步刪除、位置定位、類似結(jié)果查詢等等。
3.如何改進(jìn)或提升這種圖形和屬性的異步刷新帶來的用戶體驗?
博客園鏈接:http://www.cnblogs.com/flyingis/archive/2007/09/06/884609.html