由于ArcGIS Engine的32位、部署繁重、不适应新一代Web GIS的发展等缺点,Esri推出了ArcGIS Runtime产品,该产品因其64位、部署轻便、跨平台、更好地适应新一代Web GIS的发展而得到越来越多的关注,也有一部分Engine开发者正陆续迁移到Runtime上来。对于使用ArcGIS Engine进行开发的用户来说,加载和编辑本地数据是最常用也是最基本的功能,那么Runtime中如何加载和编辑本地数据呢?我将分两篇文章进行介绍,今天先介绍ArcGIS Runtime SDK for .Net 100.6如何加载本地数据。
ArcGIS Engine中的本地数据包括shapefile、mdb、FileGDB和SDE(这里只讨论本地矢量数据,不讨论Raster),而Runtime可以加载的本地矢量数据为shapefile、Mobile Geodatabase(.geodatabase)、GeoPackage(.gpkg),FileGDB和SDE数据在Runtime中也是可以加载的,但需要先生成mpk并且借助于Local Server。这里我们只讨论常用的本地数据源——shapefile、FileGDB以及SDE在Runtime中的加载方法。
tips: Runtime中不支持mdb数据库。
一、加载shapefile
shapefile从Runtime 100.2.1版本开始支持,提供了直接的类ShapefileFeatureTable,Runtime中加载Shapefile可以参考下面代码:
// Open the shapefile
ShapefileFeatureTable myShapefile = await ShapefileFeatureTable.OpenAsync(filepath);
// Create a feature layer to display the shapefile
FeatureLayer newFeatureLayer = new FeatureLayer(myShapefile);
// Add the feature layer to the map
MyMapView.Map.OperationalLayers.Add(newFeatureLayer);
// Zoom the map to the extent of the shapefile
await MyMapView.SetViewpointGeometryAsync(newFeatureLayer.FullExtent, 50);
有了FeatureLayer就可以直接对其编辑了。
二、加载FileGDB和SDE
1,生成mpk
ArcGIS Runtime中无法像Engine一样直接加载FileGDB以及SDE数据,需要先生成mpk,如果后续要直接编辑该FileGDB以及SDE的话,那么生成的mpk中需要引用原始数据,否则会将数据复制到该mpk的FileGDB中的,编辑不会反映到原始FileGDB或SDE中。下面简单看下如何通过ArcMap制作mpk,有两种方式:一种是ArcMap的File菜单Share As中生成;另一种是通过GP工具Package Map生成,下面以File菜单中生成为例介绍。
打开ArcMap->File菜单->Share As->Map Package 则弹出下面对话框。可以将mpk上传到Online上,也可以保存在本地,这里我们保存在本地,注意勾选“Support ArcGIS Runtime”,另外,如果要直接编辑FileGDB,需要勾选“Reference all data”。Item Description里的必填项填写完毕就可以Share了,Share之前最好Analyze一下检查有无错误,有错误则按照错误提示进行修改。
tips:使用该工具之前需要先在ArcMap->Customize菜单->ArcMap Options->Sharing 页面中勾选“Enable ArcGIS Runtime Tools”,如下图:
2,Runtime中加载mpk
生成mpk之后就是加载mpk了,Runtime中加载mpk可以通过两种方式:一种通过动态地图服务图层,一种是通过要素服务图层,下面分别看一下。
(1),Local Server可以将本地mpk发布成LocalMapService,然后通过ArcGISMapImageLayer加载,注意ArcGISMapImageLayer是无法进行编辑的,官方链接。
参考代码:
if(_localServer.Status == LocalServerStatus.Started)
{
// Create a local map service from a map package on disk.
LocalMapService mapService = new LocalMapService(@"C:\Users\admin\Desktop\subway.mpk");
// Start the local service.
await mapService.StartAsync();
// If the service was not started successfully, report status and return.
if (mapService.Status != LocalServerStatus.Started)
{
MessageBox.Show("Local Server could not be started.", "Error");
return;
}
// If the service is started, get the service URL.
Uri mapServiceUrl = mapService.Url;
// Create a new ArcGISMapImageLayer.
ArcGISMapImageLayer localServiceLayer = new ArcGISMapImageLayer(mapServiceUrl)
{
// Set layer opacity to semi-transparent.
Opacity = 0.5
};
await localServiceLayer.LoadAsync();
// Add the layer to the map.
MyMapView.Map.OperationalLayers.Add(localServiceLayer);
//zoom to layer extent
await MyMapView.SetViewpointGeometryAsync(localServiceLayer.FullExtent,5);
}
tips:执行MyMapView.SetViewpointGeometryAsync(localServiceLayer.FullExtent,5);时有可能会遇到下面错误:
根据该错误信息可以判断是因为FullExtent为null,这时就会联想到Runtime的Loadable模式,需要在获取该图层的Extent之前,确保该图层已经成功加载,在前面添加await localServiceLayer.LoadAsync();代码即可。
加断点进行调试,发现Local Server会将该mpk发布成本地地图服务:
将该url输入浏览器,结果如下图:
tips: 该服务为临时服务,程序关闭即消失。
Runtime中执行结果如图:
(2),Local Server可以将本地mpk发布成LocalFeatureService,然后通过FeatureLayer加载,这种是可以直接编辑的。
参考代码:
if (_localServer.Status == LocalServerStatus.Started)
{
// Create a local feature service from a map package on disk
LocalFeatureService featureService = new LocalFeatureService(@"C:\Users\admin\Desktop\subway.mpk");
// Start the local service.
await featureService.StartAsync();
// If the service was not started successfully, report status and return.
if (featureService.Status != LocalServerStatus.Started)
{
MessageBox.Show("Local Server could not be started.", "Error");
return;
}
// If the service is started, get the service URL.
string featureServiceUrl = featureService.Url.AbsoluteUri;
// Create a new service feature table from the dataset with index 0.
ServiceFeatureTable localServiceTable = new ServiceFeatureTable(new Uri(featureServiceUrl + "/0"));
// Create a new feature layer to display the features in the table.
FeatureLayer featureLyr = new FeatureLayer(localServiceTable);
await featureLyr.LoadAsync();
// Add the layer to the map.
MyMapView.Map.OperationalLayers.Add(featureLyr);
await MyMapView.SetViewpointGeometryAsync(featureLyr.FullExtent, 5);
}
加断点进行调试,会发现Local Server会将该mpk发布成本地要素服务:
将该url输入浏览器,结果如下图:
加载SDE数据与加载FileGDB的方式一样,只不过是先将SDE中的要素类添加到ArcMap中,然后生成mpk,在Runtime加载时要注意需要安装对应数据库的64位客户端,如果SDE的数据库为oracle,那么需要安装64位oracle客户端。
写到这里,也许会有人说这样多麻烦啊,每加载一个数据就需要制作一个mpk!!!别急,Runtime提供了另一种加载FileGDB以及SDE数据源的方式,接着看。
(3)通过DynamicWorkspace的方式加载FileGDB以及SDE
通过DynamicWorkspace替换数据源来显示数据,事先需要生成任意一个mpk,然后利用LocalServer将该mpk发布成本地地图服务,最后替换里面的子图层来显示该动态工作空间中的数据。这种方法比较利于数据的查看,可以同时加载FileGDB以及SDE中的多个图层,但是由于生成的是ArcGISMapImageLayer,所以是无法编辑的。
如果是SDE的话,使用EnterpriseGeodatabaseWorkspace,用连接字符串或者.sde连接文件的绝对路径;如果是FileGDB的话,使用FileGeodatabaseWorkspace,使用该.gdb的绝对路径即可。代码附在下面了,相信您一看就明白了。此外,DynamicWorkspace不仅支持这两种Workspace,还支持ShapefileWorkspace以及RasterWorkspace,如下图:
参考代码:
await StartLocalServer();
if(_localServer.Status == LocalServerStatus.Started)
{
LocalMapService myLocalMapService = new LocalMapService(@"C:\Users\admin\Desktop\subway.mpk");
// Create an enterprise geodatabase workspace.
EnterpriseGeodatabaseWorkspace myEnterpriseGeodatabaseWorkspace = EnterpriseGeodatabaseWorkspace.CreateFromConnectionString("sde", "PASSWORD=***;INSTANCE=sde:oracle11g:192.168.100.104/orcl;USER=sde;VERSION=sde.DEFAULT");
FileGeodatabaseWorkspace fileGeodatabaseWorkspace = new FileGeodatabaseWorkspace("fileGDB", @"E:\zxy\E_new\ZhuXinying\testData\Data.gdb");
// Create an empty DynamicWorkspace and add a EnterpriseGeodatabaseWorkspace into it's collection.
List<DynamicWorkspace> myIEnumerableOfDynamicWorkpace = new List<DynamicWorkspace>();
myIEnumerableOfDynamicWorkpace.Add(myEnterpriseGeodatabaseWorkspace);
myIEnumerableOfDynamicWorkpace.Add(fileGeodatabaseWorkspace);
// Now set the DynamicWorkspace of the LocalMapService to the one just created.
myLocalMapService.SetDynamicWorkspaces(myIEnumerableOfDynamicWorkpace);
// Start the local map service.
await myLocalMapService.StartAsync();
// Create an ArcGIS map image layer using the same url as the local map service.
Esri.ArcGISRuntime.Mapping.ArcGISMapImageLayer myArcGISMapImageLayer = new Esri.ArcGISRuntime.Mapping.ArcGISMapImageLayer(myLocalMapService.Url);
myArcGISMapImageLayer.Name = "EnterpriseLayer";
// Create a simple marker symbol
SimpleMarkerSymbol mySimpleMarkerSymbol = new SimpleMarkerSymbol();
mySimpleMarkerSymbol.Color = Color.Red;
mySimpleMarkerSymbol.Size = 10;
mySimpleMarkerSymbol.Style = SimpleMarkerSymbolStyle.Circle;
// Create a simple renderer
SimpleRenderer myMarkerRenderer = new SimpleRenderer();
myMarkerRenderer.Symbol = mySimpleMarkerSymbol;
SimpleFillSymbol mySimpleFillSymbol = new SimpleFillSymbol();
mySimpleFillSymbol.Color = Color.Green;
mySimpleFillSymbol.Style = SimpleFillSymbolStyle.Cross;
SimpleRenderer myFillRenderer = new SimpleRenderer();
myFillRenderer.Symbol = mySimpleFillSymbol;
// Create a table sub-layer source using the id from the enterprise geodatabase workspace id and a specific layer in the enterprise geodatabase workspace
TableSublayerSource myTableSubLayerSource = new TableSublayerSource("sde", "sde.subway");//Fullyqualified table name
TableSublayerSource myTableSubLayerSource2 = new TableSublayerSource("fileGDB", "省界"); // Create a new ArcGIS map image sub-layer based on the table sub-layer source
ArcGISMapImageSublayer myArcGISMapImageSublayer = new ArcGISMapImageSublayer(1, myTableSubLayerSource);
ArcGISMapImageSublayer myArcGISMapImageSublayer2 = new ArcGISMapImageSublayer(2, myTableSubLayerSource2);
myArcGISMapImageSublayer.Renderer = myMarkerRenderer;
myArcGISMapImageSublayer2.Renderer = myFillRenderer;
// Add the ArcGIS map image sub-layer to the sub-layers collection of the ArcGIS map image layer
myArcGISMapImageLayer.Sublayers.Add(myArcGISMapImageSublayer);
myArcGISMapImageLayer.Sublayers.Add(myArcGISMapImageSublayer2);
await myArcGISMapImageLayer.LoadAsync();
// Add the dynamic ArcGIS map image layer to the map.
MyMapView.Map.OperationalLayers.Add(myArcGISMapImageLayer);
//await MyMapView.SetViewpointGeometryAsync(myArcGISMapImageSublayer2.FullExtent, 5);
}
Runtime中执行结果如图:
此外,目前ArcGIS Runtime 100.6也是支持Pro创建的mpkx的,生成mpkx参数如下图:
但是目前Pro 2.4中生成的mpkx中缺少msd文件,导致runtime中报错:
该问题已经确认为Pro的bug,编号为BUG-000120203:The Package Map tool in ArcGIS Pro fails to package a .msd file despite enabling Support ArcGIS Runtime and Reference all Data for Runtime in the parameters.
相信后续ArcGIS Pro版本会解决此问题,以便Runtime成功加载mpk和mpkx。就写到这里吧,如果您对Runtime中编辑本地数据感兴趣,敬请期待下一篇…