目录
[Map 3D开发实战系列] Map Resource Explorer 背景介绍--Kick off
[Map 3D开发实战系列] Map Resource Explorer 之二-- 运行和调试
[Map 3D开发实战系列] Map Resource Explorer 之三-- 添加AutoCAD风格的Palette界面
[Map 3D开发实战系列] Map Resource Explorer 之四-- Map3D开发中的WPF
[Map 3D开发实战系列] Map Resource Explorer 之五--界面设计
这篇文章中将触及到Map 3D开发的核心操作--资源操作。我们将枚举文档中所包含的所有资源,并显示到TreeView中。
为了项目组织方便,我把这些和业务逻辑相关的类放在Model目录下。在Visual Studio中添加Model目录后,在Model目录下新建一个类命名为ResourceManager,所有和Map 3D资源操作相关的方法就放在这里类里面。在编写资源操作相关方法之前,我们先为这个ResourceManager类做一个Singleton模式:
#region Singleton
private static ResourceManager _instance = null;
private ResourceManager()
{
}
public static ResourceManager Instance
{
get
{
if (_instance == null)
{
_instance = new ResourceManager();
}
return _instance;
}
}
#endregion
现在开始实现资源相关方法,在Map 3D中支持的资源类型为FeatureSource,LayerDefiniation和SymbolDefinition。要素源FeatureSource包含了连接到地理要素源相关的参数信息;图层定义LayerDefiniation包含了图层显示和样式化相关的参数;符号定义SymbolDefinition定义了显示在地图上的符号。同一个文档中可能会有多个 FeatureSource,多个图层LayerDefiniation和SymbolDefinition,所有我们可以考虑按照资源类型类组织资源在 TreeView中的显示。所以我首先要定义一下Map 3D中支持的资源类型,以Dictionary<string, string>方式返回,以便绑定到TreeView上,其中第一个参数是资源类型,第二个参数是描述信息:
/// <summary> /// Get valid resource type in Map3D /// -------------------------------------- /// FeatureSource Contains the required parameters for connecting to a geospatial feature source /// LayerDefinition Contains the required parameters for displaying and styling a layer. Layers can be drawing layers, vector layers, or grid (raster) layers. /// SymbolDefinition Defines a symbol to be displayed on a map. /// </summary> /// <returns></returns> public Dictionary<string,string> GetResourceAllTypes()
{
Dictionary<string, string> resourceTypes = new Dictionary<string, string>();
resourceTypes.Add(MgResourceType.FeatureSource, "Contains the required parameters for connecting to a geospatial feature source.");
resourceTypes.Add(MgResourceType.LayerDefinition, "Contains the required parameters for displaying and styling a layer. Layers can be drawing layers, vector layers, or grid (raster) layers.");
resourceTypes.Add(MgResourceType.SymbolDefinition, "Defines a symbol to be displayed on a map.");
return resourceTypes;
}
下面我们把资源类型作为treeview的节点绑定到TreeView界面上。在我们的自定义WPF用户控件的后台代码ExplorerForm.xaml.cs中定义BindTreeView方法,调用ResourceManager中定义的GetResourceAllTypes方法获取所有Map 3D支持的资源类型字典。然后把这个字典绑定到treeview控件上,把资源类型作为TreeViewItem的Header显示,把描述信息作为ToolTip。
public void ForceRefresh()
{
if (this.IsVisible)
{
BindTreeView(treeView1);
}
}
private void BindTreeView(TreeView tree)
{
tree.Items.Clear();
ResourceManager resourceMgr = ResourceManager.Instance;
Dictionary<string, string> resourceTypes = resourceMgr.GetResourceAllTypes();
foreach (var resType in resourceTypes)
{
TreeViewItem resourceTypeitem = new TreeViewItem();
resourceTypeitem.Header = resType.Key;
resourceTypeitem.ToolTip = resType.Value;
//Bind resource to resourceItemType Dictionary<string, string> resList = resourceMgr.GetResourcesByType(resType.Key);
tree.Items.Add(resourceTypeitem);
}
}
现在运行一下,我们的资源浏览器应该已经初见雏形了,如图:
好了,现在来按照资源类型来枚举文档library中包含的所有资源。Map 3D采用Geospatial Platform API中的资源服务来枚举所有的资源。我们首先要创建资源服务,在Map 3D中创建资源服务于MapGuide中略有不同。在MapGuide中,资源服务是有SiteConnection.CreateService方法创建出来的,而在Map 3D中是通过AcMapServiceFactory的静态方法GetService来创建的:
public MgResourceService ResourceService
{
get
{
if (_resourceService == null)
{
_resourceService = AcMapServiceFactory.GetService(MgServiceType.ResourceService) as MgResourceService;
}
return _resourceService;
}
}
现在有了资源服务,就可以通过MgResourceService::EnumerateResources方法来枚举所有资源了,下面是摘自帮助文档中关于EnumerateResources方法的描述。传入要枚举的资源ID,如果要枚举资源库中所有的资源resourceID可以是Library://. 也可以指定资源类型来枚特定类型的资源。函数的返回值是一个MgByteReader对象,里面包含了XML表示的资源列表。
.NET Syntax
MgByteReader EnumerateResources(MgResourceIdentifier resource, int depth, string type);
resource
(MgResourceIdentifier) Resource identifier specifying the resource to enumerate. This can be a document or a folder.
If it is a folder, you must include the trailing slash in the identifier.
depth
(int) Recursion depth, relative to the specified resource.
type
(String/string) Type of the resource to be enumerated. (Case sensitive.) See MgResourceType for valid types.
Or, this can be set to null, in which case information about all resource types is returned.
下面是运行过程中MgResourceService::EnumerateResources方法返回的XMl的一个例子,我们可以通过DOM来解析XML,找到我们的需要的资源ID。
-----------------------------------
<?xml version="1.0" encoding="UTF-8"?> <ResourceList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ResourceList-1.0.0.xsd"> <ResourceDocument> <ResourceId>Library://erase.FeatureSource</ResourceId> <Depth>1</Depth> <Owner></Owner> <CreatedDate>2011-02-07T06:27:24.062153Z</CreatedDate> <ModifiedDate>2011-02-07T06:27:24.062153Z</ModifiedDate> <ResourceDocumentHeader xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ResourceDocumentHeader-1.0.0.xsd"> <General> <IconName></IconName> </General> <Security xsi:noNamespaceSchemaLocation="ResourceSecurity-1.0.0.xsd"> <Inherited>true</Inherited> <Groups> <Group> <Name>Everyone</Name> <Permissions>r,w</Permissions> </Group> </Groups> </Security> </ResourceDocumentHeader> </ResourceDocument> <ResourceDocument> <ResourceId>Library://intersect2.FeatureSource</ResourceId> <Depth>1</Depth> <Owner></Owner> <CreatedDate>2011-02-07T06:27:16.857741Z</CreatedDate> <ModifiedDate>2011-02-07T06:27:16.857741Z</ModifiedDate> <ResourceDocumentHeader xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ResourceDocumentHeader-1.0.0.xsd"> <General> <IconName></IconName> </General> <Security xsi:noNamespaceSchemaLocation="ResourceSecurity-1.0.0.xsd"> <Inherited>true</Inherited> <Groups> <Group> <Name>Everyone</Name> <Permissions>r,w</Permissions> </Group> </Groups> </Security> </ResourceDocumentHeader> </ResourceDocument> <ResourceDocument> <ResourceId>Library://realtor_neighborhoods.FeatureSource</ResourceId> <Depth>1</Depth> <Owner></Owner> <CreatedDate>2011-02-07T06:26:52.00632Z</CreatedDate> <ModifiedDate>2011-02-07T06:26:52.00632Z</ModifiedDate> <ResourceDocumentHeader xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ResourceDocumentHeader-1.0.0.xsd"> <General> <IconName></IconName> </General> <Security xsi:noNamespaceSchemaLocation="ResourceSecurity-1.0.0.xsd"> <Inherited>true</Inherited> <Groups> <Group> <Name>Everyone</Name> <Permissions>r,w</Permissions> </Group> </Groups> </Security> </ResourceDocumentHeader> </ResourceDocument> <ResourceDocument> <ResourceId>Library://sfzipcodes.FeatureSource</ResourceId> <Depth>1</Depth> <Owner></Owner> <CreatedDate>2011-02-07T06:26:53.154385Z</CreatedDate> <ModifiedDate>2011-02-07T06:26:53.154385Z</ModifiedDate> <ResourceDocumentHeader xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ResourceDocumentHeader-1.0.0.xsd"> <General> <IconName></IconName> </General> <Security xsi:noNamespaceSchemaLocation="ResourceSecurity-1.0.0.xsd"> <Inherited>true</Inherited> <Groups> <Group> <Name>Everyone</Name> <Permissions>r,w</Permissions> </Group> </Groups> </Security> </ResourceDocumentHeader> </ResourceDocument> </ResourceList>
我们在ResourceManager类中添加下面的方法来枚举资源库中的指定类型的资源,通过XML解析后存入一个Dictionary中返回,字典的第一个参数是资源名字用来显示,第二个参数是resourceID,用来进行后续存取资源内容时使用。
public Dictionary<string, string> GetResourcesByType(string resourceType)
{
//TODO: if (!IsValidMap3DResourceType(resourceType))
{
throw new ApplicationException("unspported resource type by Map3D");
}
Dictionary<string, string> resources = new Dictionary<string, string>();
MgResourceIdentifier rootResId = new MgResourceIdentifier(@"Library://");
MgByteReader reader = ResourceService.EnumerateResources(rootResId, -1, resourceType.ToString());
//Convert to string String resStr = reader.ToString(); //Load into XML document so we can parse and get the names of the maps XmlDocument doc = new XmlDocument();
doc.LoadXml(resStr);
//let's extract the map names and list them XmlNodeList resIdNodeList; XmlElement root = doc.DocumentElement; resIdNodeList = root.SelectNodes("//ResourceId");
int resCount = resIdNodeList.Count;
for (int i = 0; i < resCount; i++)
{
XmlNode resIdNode = resIdNodeList.Item(i);
String resId = resIdNode.InnerText;
int index1 = resId.LastIndexOf('/') + 1;
int index2 = resId.IndexOf(resourceType) - 2;
int length = index2 - index1 + 1;
string resName = resId.Substring(index1, length);
resources.Add(resName, resId);
}
return resources;
}
好了,然后我们把枚举到的资源也作为treeviewitem绑定到treeview控件上。修改上面的BingTreeView方法如下:
private void BindTreeView(TreeView tree)
{
tree.Items.Clear();
ResourceManager resourceMgr = ResourceManager.Instance;
Dictionary<string, string> resourceTypes = resourceMgr.GetResourceAllTypes();
foreach (var resType in resourceTypes)
{
TreeViewItem resourceTypeitem = new TreeViewItem();
resourceTypeitem.Header = resType.Key;
resourceTypeitem.ToolTip = resType.Value;
//Bind resource to resourceItemType Dictionary<string, string> resList = resourceMgr.GetResourcesByType(resType.Key);
foreach (var item in resList)
{
TreeViewItem resItem = new TreeViewItem();
resItem.Header = item.Key;
resItem.ToolTip = item.Value;
resItem.Tag = "IsResource";
resourceTypeitem.Items.Add(resItem);
} tree.Items.Add(resourceTypeitem); } }
好了,编译一下如果没什么问题的话我们的工作已经完成一半了,通过netload命令加载程序集并调出ResourceExplorer界面后,你应该能看到类似下面的界面:
好了,先到这儿吧,下来我们该准备后续的关于资源内容方面的操作了。请继续关注。
Cheers,
峻祁连