ArcGIS Server 10.1 最大的功能改进之一:动态图层,可以实现地图服务动态添加数据、动态改变图层顺序、动态改变渲染等很强大的功能。
Silverlight API 3.0 之后的版本,实现了对动态图层操作的支持,API中主要新增了两个类:
DynamicLayerInfo
以及
LayerDrawingOptions
简单的说, DynamicLayerInfo主要用来添加动态图层数据,LayerDrawingOptions主要用来更改图层渲染,改变图层顺序。
关于动态图层的具体使用方法,可以参考http://resources.arcgis.com/en/help/silverlight-api/samples/start.htm#DynamicLayer
然而以上都是针对动态地图服务的(Dynamic Map Service),即客户端收到的都是一张export出来的图片,那么我能不能把动态图层作为feature Layer来查询,取回属性和要素呢?答案是肯定的,参考 Rest API 10.1帮助,http://resources.arcgis.com/en/help/rest/apiref/dynamicLayer.html dynamiclayer 有query 方法,而且给出了查询的语法,对于这种很自然的需求,让人蛋疼的是,Silverlight API中,竟然没有对应的查询方法。
我们先来看REST 目录中动态图层的查询方法,
要构造一个动态图层,必须给动态地图服务传一个正确的参数layer:参考下图
这个参数指定了动态图层的类型,以及动态图层的数据源。在网页底部,我们能够找到Query方法:
进去以后,我们就能进行动态图层的查询了:
注意其中的url,对动态图层的查询就是对 dynamicLayer 资源做 query方法,其中参数 layer必须填对。
下 面来到客户端,让人蛋疼的是,客户端的 QueryTask 以及 Query 查询参数这两个都不支持动态图层,肿么办,自己写吧。首先,我们需要拼出正确的layer参数,实际上就是把DynamicLayerInfo给序列化了 (可惜DynamicLayerInfo内部序列化的方法SL API也没有暴露出来),以下是把DynamicLayerInfo 对象序列化为 layer 参数的扩展方法:
(更新,DataSource 基类有ToJson 的public方法,它的4种子类JoinDataSource, RasterDataSource, TableDataSouce , QueryDataSource都重载了这个方法,所以下面代码中source 的json部分就不用自己拼了,只需要加上id就行)
public static class Extension
{
public static string ToLayerString(this DynamicLayerInfo info)
{
StringBuilder sb = new StringBuilder();
//sb.Append("?layer={\"id\":");
sb.Append("&layer={\"id\":");
sb.Append(info.ID.ToString());
sb.Append(",\"source\":{\"type\":");
sb.Append(GetDLISourceType(info));
switch (GetDLISourceType(info))
{
case "\"mapLayer\"":
sb.Append(",\"mapLayerId\":");
sb.Append((info.Source as LayerMapSource).MapLayerID.ToString());
sb.Append("}}");
break;
default:
sb.Append(",\"dataSource\":{\"type\":\"table\",\"workspaceId\":\"");
sb.Append(((info.Source as LayerDataSource).DataSource as TableDataSource).WorkspaceID);
sb.Append("\",\"dataSourceName\":\"");
sb.Append(((info.Source as LayerDataSource).DataSource as TableDataSource).DataSourceName);
sb.Append("\"}}}");
break;
}
return sb.ToString();
}
public static string GetDLISourceType(DynamicLayerInfo info)
{
if (info.Source is LayerDataSource)
{
return "\"dataLayer\"";
}
else
return "\"mapLayer\"";
}
}
然后又来到了QueryTask, Silverlight的QueryTask 写的非常的死,它就直接把传给它的URL 加上/query 然后加上查询Query参数的各种字符串,见反编译截图
所以不论我怎么传QueryTask 的URL ,例如:http://xxx.MapServer/dynamicLayer?layer= info.ToLayerString()这样的URL QueryTask 会直接再后面加上/query 以及查询参数,导致查询失败,因为QueryTask没有自动把layer 参数给移到query之后的逻辑,顺带说一句,JavaScript可以这么传URL, 它的QueryTask 有处理dynamicLayer的逻辑,本来想直接扩展ExecuteAsync方法的,无奈其中调用的都是各种 privateinternal方法,只好抛弃这条途径,直接调用WebClient,构造QueryTask的一个扩展方法;
public static void ExecuteAsyncExtension(this QueryTask qt, Query para, DynamicLayerInfo info, DownloadStringCompletedEventHandler queryCompleteCallBack)
{
var url = qt.GetRequestUri(para).ToString() + info.ToLayerString();
WebClient wc = new WebClient();
wc.DownloadStringAsync(new Uri(url));
wc.DownloadStringCompleted += queryCompleteCallBack;
}
这个方法接受3个参数,Query 查询参数, DynamicLayerInfo 动态图层信息, 以及查询完成回调函数的delegate,这样在实际使用中,我们可以象普通的查询一样,设定查询的参数,然后查询:
另外要注意的是,webclient download的回来是纯json,我们还需要使用FeatureSet 的FromJson静态方法来反序列化获得要素的对象:
测试结果图,注意蓝色是动态图层 (image) 红色的是graphicLayer