MapGuide开发实例----程序实现切换地图
我们在前面的文章中讲WebLayout(MapGuide应用开发系列(九)—- MapGuide Studio准备地图之网页布局)的时候卖了个关子,提到可以通过程序更改WebLayout的xml表示来达到通过程序切换地图的目的。今天我们就来讲一下具体如何实现。
我们在前面的文章中讲WebLayout(MapGuide应用开发系列(九)—- MapGuide Studio准备地图之网页布局)的时候卖了个关子,提到可以通过程序更改WebLayout的xml表示来达到通过程序切换地图的目的。今天我们就来讲一下具体如何实现。
我在前面的文章中讲过资源的概念,WebLayout也是资源的一种,也是由XML定义的。而且我们还知道资源直接是有引用关系的,网页布局WebLayout中就引用了地图资源。MapGuide提供了一套完整的WebExtension API,其中对于资源的操作就要用的资源服务(ResourceService)。下面是我们将要用到的资源服务API的几个重要方法:
.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }
//枚举知道资源ID下的所有资源 MgByteReader EnumerateResources(MgResourceIdentifier resource, int depth, string type);
//获取资源的内容 MgByteReader GetResourceContent(MgResourceIdentifier resource ); //为指定资源ID的资源设置资源内容和资源头,可用来更新资源 void SetResource(MgResourceIdentifier resource, MgByteReader content, MgByteReader header);
.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }
然后还是重温一下WebLayout的XML定义中关于Map的部分,了解我们在使用程序切换地图的时候应该朝哪部分下手:)
<?xml version="1.0" encoding="utf-8"?> <WebLayout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="WebLayout-1.0.0.xsd"> <Title>Sheboygan Map</Title> <Map> <ResourceId>Library://Samples/Sheboygan/MapsTiled/Sheboygan.MapDefinition</ResourceId> <HyperlinkTarget>TaskPane</HyperlinkTarget> </Map>
.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }
好了准备就绪,开始动手了. 我们想要在任务栏中添加一个按钮,点击这个按钮引发到一个页面,在这个页面加载的时候枚举MapGuide 服务器上所有可用的MapDefinition 添加到一个下拉框中的,然后用户可以选择任意一个地图,实现地图的自动切换.这就是我们要做的工作.
第一步, 要在MapGuide Studio中添加一个Invoke URL的命令,并添加到任务栏Taskbar或者工具栏ToolBar中. 定义这个命令将引发的URL为http://www.cnblogs.com/SwitchMaps/SwitchMapsUI.aspx, 这里是相当MapGuide view的相对路径.并且注意到下面Display result in this target interface我们选择的是 Task Pane,显示在任务面板中.你也可以在这里指定其他的frame名从而显示到不同的框架中.
然后我们打开Visual Studio 2005或者VS 2008, 在本地IIS上创建一个Web站点, http://localhost/SwitchMaps/, 创建成功后在IIS中应该是这样的,注意SwitchMaps虚拟目录和MapGuide2010虚拟目录的相对位置,并结合我们上面的URL设置http://www.cnblogs.com/SwitchMaps/SwitchMapsUI.aspx来对照理解这个URL的写法。
要在Visual Studio里开发基于MapGuide的应用程序,当然要添加MapGuide相关dll的引用,我们可以创建一个bin目录,然后把C:\Program Files\Autodesk\MapGuideEnterprise2010\WebServerExtensions\www\mapviewernet\bin下所有的dll拷贝到应用程序的bin目录下。
首页中加入我们的MapGuide Ajax Viewer,如下:
<%@ Page Language="C#" %> <%@ Import Namespace="OSGeo.MapGuide" %> <% Utility utility = new Utility();
String webLayout = "Library://Samples/Sheboygan/Layouts/SheboyganAsp.WebLayout";
Session["InitWebLayout"] = webLayout; // for convenience, I put the weblayer into Session
String sessionId = "";
try { utility.InitializeWebTier(Request); MgUserInformation userInfo = new MgUserInformation("Anonymous", "");
MgSite site = new MgSite();
site.Open(userInfo);
sessionId = site.CreateSession();
}
catch (MgException mge)
{
Response.Write(mge.GetMessage());
Response.Write(mge.GetDetails());
}
finally { } %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Viewer Sample Application</title> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/> <meta http-equiv="content-script-type" content="text/javascript" /> <meta http-equiv="content-style-type" content="text/css" /> </head> <frameset rows="0,*" border="0" framespacing="0"> <frame /> <frame src="/mapguide2010/mapviewernet/ajaxviewer.aspx?SESSION=<%= sessionId %>&WEBLAYOUT=<%= webLayout %>" name="ViewerFrame" id = "ViewerFrame" /> </frameset> <script> </script> </html>
.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }
然后我们创建一个页面SwitchMapsUI.aspx.这个页面的实现才是我们今天要讲述的重点。为了演示,界面设计很简单,就一个ComboBox和一个Button。我们看一下重点代码:
这是获取指定资源目录下的所有地图资源:
/// <summary> /// enumberate all the map definitions in the /// </summary> /// <param name="resId"></param> /// <returns></returns> public Dictionary<string, string> GetAllMaps(MgResourceIdentifier resId)
{
Dictionary<string, string> mapList = new Dictionary<string, string>();
MgResourceService resSvc = siteConnection.CreateService(MgServiceType.ResourceService) as MgResourceService;
// Get all map def resources MgByteReader byteRdr = resSvc.EnumerateResources(resId, -1, MgResourceType.MapDefinition); //Convert to string String MapResStr = byteRdr.ToString(); //Load into XML document so we can parse and get the names of the maps XmlDocument doc = new XmlDocument();
doc.LoadXml(MapResStr);
//let\'s extract the map names and list them XmlNodeList MapResIdNodeList; XmlElement root = doc.DocumentElement; MapResIdNodeList = root.SelectNodes("//ResourceId");
int nRes = MapResIdNodeList.Count;
for (int i = 0; i < nRes; i++)
{
XmlNode MapResIdNode = MapResIdNodeList.Item(i);
String MapRes = MapResIdNode.InnerText;
int index1 = MapRes.LastIndexOf(\'/\') + 1;
int index2 = MapRes.IndexOf("MapDefinition") - 2;
int length = index2 - index1 + 1;
string mapName = MapRes.Substring(index1, length);
if (!mapList.ContainsKey(mapName))
{
mapList.Add(mapName, MapRes);
}
}
return mapList;
}
.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }
下面是通过资源服务API,首先读取出WebLayout资源的xml表示,通过在DOM中查找替换<ResourceId>节点的内容,然后在更新回到一个会话资源中,并返回这个会话资源的资源ID。 为什么要更新到一个会话资源中呢?我们开发的是WebGIS系统,你肯定不希望一个用户在调用你这个功能切换地图时,把所有在使用这个地图服务的用户的地图全部切换了吧,那样用户是不是会觉得很恐怖:)
/// <summary> /// Edit the weblayout resource content to change map /// </summary> /// <param name="webLayout">the resourece id of weblayout</param> /// <param name="sessionId">current session string</param> /// <param name="mapDefResourceId">resource id of map definition</param> /// <returns></returns> public string SwitchMapsInWebLayout(string webLayout, string sessionId, string mapDefResourceId)
{
MgResourceIdentifier layoutResId = new MgResourceIdentifier(webLayout);
MgResourceService resSvc = siteConnection.CreateService(MgServiceType.ResourceService) as MgResourceService;
//the resource content of WebLayout MgByteReader reader = resSvc.GetResourceContent(layoutResId); string layoutXml = reader.ToString();
//Edit the map resource in XmlDocument in DOM XmlDocument doc = new XmlDocument();
doc.LoadXml(layoutXml);
XmlNode nodeCenterX = doc.GetElementsByTagName("ResourceId").Item(0);
nodeCenterX.InnerText = mapDefResourceId;
MgByteSource byteSource = ByteSourceFromXMLDoc(doc);
string sessionLayoutName = layoutResId.GetName();
string sessionLayout = "Session:" + sessionId + @"//" + sessionLayoutName + ".WebLayout";
MgResourceIdentifier sessionLayoutResId = new MgResourceIdentifier(sessionLayout);
//update back to a session weblayout resSvc.SetResource(sessionLayoutResId, byteSource.GetReader(), null);
return sessionLayout;
}
.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }
最后为了让更改在界面上起作用,真正切换地图,我们需要更新MapGuide Viewer的WebLayout参数,并使之刷新从而重新加载更改过的地图:
protected void Button1_Click(object sender, EventArgs e)
{
Response.Write(ddlMaps.SelectedValue);
Utility utility = new Utility();
string session = Session["MgSession"].ToString();
utility.ConnectToServer(session);
string webLayout = Session["InitWebLayout"].ToString();
string sessionLayout = utility.SwitchMapsInWebLayout(webLayout, session, ddlMaps.SelectedValue);
string viewerPath = string.Format(viewerPathSchema, session, sessionLayout);
string code = "<script>parent.parent.parent.frames(\'ViewerFrame\').location.href = \'" + viewerPath + "\'; </script>";
Response.Write(code);
}
.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }
好了,大功告成,我们看一下效果吧:
初始地图,页面加载枚举出所有可用地图:
地图切换后,注意到我们自定义的命令SwitchMap还在哦 :)
好了,通过这个例子,大家应该能知道如果运用ResourceService对资源进行相关修改更新的操作。以后的应用就看你的想象力了 :) Go MapGuiding !
完整代码下载: SwitchMaps.zip
有任何意见建议欢迎评论或到MGDN论坛讨论。
转载请注明出处及作者 峻祁连 Daniel Du 杜长宇