进阶应用开发

最后更新时间:2019年8月16日

4.1 自定义地图视图

4.1.1 示例功能概述

实现功能:打开地图文档,并显示该地图文档里的第一个地图。

效果预览如下图所示:

开始界面

图 4-1开始界面

打开地图文档示意图

图 4-2 打开地图文档示意图

4.1.2 实现思路及关键代码

插件项:MenuBar(菜单栏)、Command(命令按钮)、DockWindow(停靠窗口)、MapContentsView(地图视图)。

步骤一:打开VS 2010新建一个MapGIS项目,命名为“CustomMapViewDemo”,在该MapGIS插件项目中创建一个MenuBar菜单栏,将Name属性值设为“MapOperationMB”,Caption属性值设为“进阶应用”;添加一个Command插件项(命名为“OpenDocCmd”)打开地图文档视图功能;添加一个MapContentsView插件项(命名为“MapContentsView”)用于承载地图视图控件;在VS 2010中自定义一个用户控件,命名为“UserControl1”,在控件窗体中拖入一个地图视图MapControl控件,设置其Modifiers属性为public,Dock属性为Fill;

步骤二:将OpenDocCmd命令按钮插件项添加到MapOperationMB菜单项中,具体实现代码请参考1.2小节的内容;

步骤三:将UserControl1自定义用户控件绑定到MapContentsView地图视图插件项中,具体实现步骤如下。

(1) 在MapContentsView.cs文件中定义一个自定义用户控件(UserControl1对象) userControl的全局变量;

(2) 修改MapContentsView.cs文件中的ObjecthWnd属性代码如下所示:

程序代码 4 1 修改ObjecthWnd属性代码

       public Control ObjecthWnd
        {
            get { return userControl; }
        }

(3) 修改MapControl属性代码如下所示之后就完成了绑定功能。 程序代码 4 2 修改MapControl属性代码

       public MapGIS.GISControl.MapControl MapControl
        {
            get { return userControl.mapControl1; }
        }

步骤四:在OpenDocCmd.cs文件中实现打开地图文档,并显示该地图文档里的第一个地图功能,具体步骤如下。

(1) 在OpenDocCmd.cs文件中定义一个应用框架(IApplication对象)hk全局变量,定 义一个地图视图控件(MapControl对象)mapCtrl全局变量,获取插件容器中的地图视图插件MapContentsView对象,然后根据地图视图插件MapContentsView对象来获取对应的MapContorl地图视图控件对象,在OnCreate方法中的关键代码如下:

程序代码 4 3 获取MapControl控件关键代码

       public void OnCreate(IApplication hook)
        {
            hk = hook;

            //内容视图控件
            IContentsView cv = null;
            //获取指定的内容视图控件            hk.PluginContainer.ContentsViews.TryGetValue("CustomMapViewDemo.MapContentsView", out cv);
            //获取地图视图插件项
            IMapContentsView mapview = cv as IMapContentsView;

            //获取该视图的MapControl属性
            mapCtrl = mapview.MapControl;
        }

(2) 打开地图文档,将地图文档中的第一个地图显示到MapControl中,在OnClick方法中关键代码如下:

程序代码 4 4 显示地图关键代码

     public void OnClick()
        {
            Map map = null;
            string docName = null;

            if (mapCtrl == null) return;
            Document doc = this.hk.Document;
            
            //选择打开地图文档
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Multiselect = true;
            ofd.Filter = "(地图文档mapx)|*.mapx|(地图map)|*.map";

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                //获取打开的地图文档的名称
                docName = ofd.FileName; 
            }
            if (doc == null) return;

            doc.Open(docName);
            Maps maps = doc.GetMaps();
            if (maps.Count > 0)
            {
                //获取当前第一个地图
                map = maps.GetMap(0);
                //设置地图的第一个图层为激活状态
                map.get_Layer(0).State = LayerState.Active;
                mapCtrl.ActiveMap = map;
                mapCtrl.Restore();
            }            
        }

步骤五:在MapGIS.AppLoader.exe上面加载完MapGIS.WorkSpace.Plugin.dll此库后,用户单击“打开地图文档”,打开地图文档,并显示该地图文档里的第一个地图。

4.2 交互式几何查询

4.2.1 示例功能概述

实现功能:用户在默认地图窗口中拉框查询,闪烁查询结果,属性列表中显示当前被查询中的第一个激活图层中的记录属性。 效果预览如下图所示:

打开一幅地图界面示意图

图 4-3 打开一幅地图界面示意图

拉框查询示意图

图 4-4 拉框查询示意图

查询居民地结果图

图 4-5 查询居民地结果图

4.2.2 实现思路及关键代码

插件项:MenuBar(菜单栏)、Command(命令按钮)、DockWindow(停靠窗口)。

步骤一:打开VS 2010新建一个MapGIS项目,命名为“InterGeomQuery”,在该MapGIS插件项目中创建一个MenuBar菜单栏,将Name属性值设为“SetBasToolMBar”,Caption属性值设为“查询方式”;添加2个Command插件项(命名为“QueryByRectCmd”,“QueryByCirCmd”)分别实现矩形查询和圆查询的功能;添加一个DockWindow插件项(命名为“DockWindow”)用于承载属性视图控件;在VS 2010中自定义一个用户控件,命名为“AttUserControl”,在控件窗体中拖入一个属性视图AttControl控件,设置其Modifiers属性为public,Dock属性为Fill;

步骤二:将QueryByRectCmd和QueryByCirCmd两个命令按钮插件项添加到SetBasToolMBar菜单项中,具体实现代码请参考3.2小节的内容;

步骤三:将AttUserControl自定义用户控件绑定到DockWindow停靠窗口插件项中,具体实现步骤如下。

(1) 在DockWindow.cs文件中自定义一个属性视图控件(AttUserControl对象)attCtrl 全局变量;

(2) 修改ChildHWND属性字段代码如下所示,即可实现绑定功能:

程序代码 4 5 修改ChildHWND属性字段代码

       public Control ChildHWND
        {
            get { return attCtrl; }
        }

步骤四:创建自定义类,命名为“SelectToolClass”,该类继承并重写GISBasTool 类,在SelectToolClass类定义一个选择工具控件(SelectTool对象 )selTool全局变量,注册selTool的选择事件,并在事件中完成查询功能,关键代码如下:

程序代码 4 6 SelectToolClass类中的全局变量

        //地图视图控件
        MapControl mapCtrl;
        //交互工具:选择工具控件
        SelectTool selTool;
        //选择数据时的数据类型过滤 
        SelectDataType dataType;
        //地理类对象基类接口 
        IBasCls basClass = null;
        //结果集对象
        RecordSet rcdSet = null;
        //属性视图控件
        AttControl attCtrl = null;
        //查询选择方式:圆选择、多边形选择、矩形选择 
        SelectType selType;    

程序代码 4 7 SelectToolClass类的构造函数代码

        /// 
        /// 实现拉框选择查询
        /// 
        /// 地图视图控件
        /// 选择数据时的数据类型过滤
        /// 属性视图控件
        /// 查询选择方式:矩形选择 
        public SelectToolClass(MapControl control, SelectDataType dataType, AttControl attctr,SelectType seltype)
            : base()
        {
           
            this.mapCtrl = control;
            this.dataType = dataType;
            this.attCtrl = attctr;
            this.selType = seltype;

            //查询选择项
            SelectOption selOpt = new SelectOption();
            selOpt.DataType = dataType;  //选择数据时的类型过滤类型  
            selOpt.SelMode = SelectMode.Multiply; //选择模式  
            selOpt.UnMode = UnionMode.Copy;  //结果数据合并模式  
            selOpt.LayerCtrl = SelectLayerControl.Editable; //选择数据时的图层过滤类型 

            //创建圆交互工具
            selTool = new SelectTool(control, selType, selOpt, SpaQueryMode.MBRIntersect, control.Transformation);
            //注册选择事件
            selTool.Selected += new SelectTool.SelectHandler(selTool_Selected);    
        }

程序代码 4 8 SelectTool的Selected事件响应关键代码

       void selTool_Selected(object sender, SelectEventArgs e)
        {            
            if (e.SelSet != null)
            {
                this.mapCtrl.FlashSelectSet();
                int objCount = getSelectSetCount(e.SelSet);
                MessageBox.Show("共选择了" + objCount + "个图元");
            }            
        }

程序代码 4 9获取选择集中的个数中的关键代码

       /// 
       /// 获取选择集中的个数
       /// 
       /// 选择集对象
       /// 选择集中的个数
       public int getSelectSetCount(SelectSet set)
        {
            int count = 0;
            //记录符合选择项的ids
            ObjectIDs oids = new ObjectIDs(); 
            ObjectID oid = new ObjectID();

            if (set != null)
            {
                //获取选择集列表
                List lst = set.Get(); 
                
                foreach (SelectSetItem item in lst)
                {
                    count += item.IDList.Count;
                }
                if (lst == null || lst.Count == 0) return count;

                //获取图层信息
                MapLayer maplayer = lst[0].Layer;
                //获取图层对应的要素类的信息
                basClass = maplayer.GetData();

                //获取处于编辑状态第一个图层的要素ID列表
                List idArr = lst[0].IDList;  
                
                for (int i = 0; i < idArr.Count; i++)
                {
                    oid.Int64Val = idArr[i];
                    oids.Append(oid);  
                }
                rcdSet = new RecordSet(basClass);
                //添加结果集
                rcdSet.AddSet(oids);
            }
            attCtrl.SetXCls((IVectorCls)basClass, rcdSet);
            return count;
        }

步骤四:实现查询功能,以矩形查询为例进行说明,在QueryByRectCmd插件中的 OnCreate方法中获取当前地图视图控件MapControl对象,以及获取DockWindow插件所绑定的属性视图控件AttControl对象,具体代码如下所示:

程序代码 4 10 OnCreate方法关键代码

        public void OnCreate(IApplication hook)
        {
            hk = hook;
            //获取DockWindow插件            hk.PluginContainer.DockWindows.TryGetValue("InterGeomQuery.DockWindow", out dw);
            //通过停靠窗口来获取用户控件中的属性控件对象
            attCtrl = (dw.ChildHWND as AttUserControl).attControl1;
            //获取当前激活视图的MapControl属性
            IMapContentsView mapConView = null;
            mapConView = hk.ActiveContentsView as IMapContentsView;
            if (mapConView == null) return;
            mapCtrl = mapConView.MapControl;
            mapCtrl.Restore();
        }

步骤五:在QueryByRectCmd插件中的OnClick方法中实现矩形查询,具体代码如下所示:

程序代码 4 11 OnClick方法中的关键代码

       public void OnClick()
        {
            //设置为拉框查询
            SelectType seltype = SelectType.Rectangle;

            IMapContentsView mapConView = null;
            mapConView = hk.ActiveContentsView as IMapContentsView;
            if (mapConView == null) return;
            //获取当前激活视图的MapControl属性
            mapCtrl = (hk.ActiveContentsView as IMapContentsView).MapControl;

            //创建拉框选择类对象
            SelectToolClass basTool = new SelectToolClass(mapCtrl, SelectDataType.Anyone, attCtrl, seltype);
            mapCtrl.SetBasTool(basTool);

            if (attCtrl == null) return;
            this.attCtrl.AttLButtonDown += new AttControl.AttLBtDownEventHandler(attctrl_AttLButtonDown);
        }

步骤六:在MapGIS.AppLoader.exe上面加载完MapGIS.WorkSpace.Plugin.dll,InterGeomQuery.dll这个2个库后,就可以实现查询功能。

4.3 插件间通讯

4.3.1 示例功能概述

实现功能:插件间通讯,主要是调用目标插件的资源,如方法等;本示例功能为通过插件容器获取MapGIS.WorkSpace.Plugin插件中的CmdOpen命令按钮插件来打开一个地图文档。

效果预览如下图所示:

插件间通讯示意图

图 4-6插件间通讯示意图

点击命令按钮示意图

图 4-7点击命令按钮示意图

4.3.2 实现思路及关键代码

插件项:MenuBar(菜单栏)、Command(命令按钮)。

步骤一:打开VS 2010新建一个MapGIS项目,命名为“PluginInteraction”,在该MapGIS插件项目中创建一个MenuBar菜单栏,将Name属性值设为“PluginMenuBar”,Caption属性值设为“插件交互”;添加1个Command插件项(命名为“OpenCmd”)实现打开地图文档的功能;

步骤二:将QueryByRectCmd命令按钮插件项添加到PluginMenuBar菜单项中,具体实现代码请参考1.2小节的内容;

步骤三:定义一个命令按钮插件(ICommand对象)cmd,通过插件容器获取MapGIS.WorkSpace.Plugin插件中的CmdOpen命令按钮插件,将该插件传给cmd对象,调用cmd插件的OnClick方法打开地图文档,关键代码如下所示:

程序代码 4 12 OnClick方法实现打开地图文档代码

        public void OnClick()
        {
            //命名按钮插件对象
            ICommand cmd = null;
            //通过插件容器获取MapGIS.WorkSpace.Plugin插件中的CmdOpen命令按钮插件            hk.PluginContainer.Commands.TryGetValue("MapGIS.WorkSpace.Plugin.CmdOpen", out cmd);
            //获取成功
            if (cmd != null)
            {
                //打开地图文档
                cmd.OnClick();

                //获取打开的地图文档对象
                Document doc = hk.Document;
                //获取第一个地图
                Map map = doc.GetMaps().GetMap(0);
                if (map == null) return;

                //在地图视图上显示第一个地图                hk.WorkSpaceEngine.FireMenuItemClickEvent("MapGIS.WorkSpace.Style.PreviewMap", map); 
        }

步骤四:在MapGIS.AppLoader.exe上面加载完MapGIS.WorkSpace.Plugin.dll,CustomMapViewDemo.dll和MapGIS.MapEditor.Plugin.dll这个2个库后,就可以实现查询功能。

4.4 自定义工作空间

4.4.1 示例功能概述

实现功能:自定义工作空间的开发,涉及停靠窗口(IDockWindw)插件的开发,以及工作空间目录树中地图节点的显示,目录树右键菜单的维护等;主要借助平台提供的MapGIS.UI.Controls 程序集里的MapWorkSpaceTree 类实现目录树的构建。

效果预览如下图所示:

自定义工作空间示意图

图 4-8 自定义工作空间示意图

4.4.2 实现思路及关键代码

步骤一:打开VS 2010新建一个MapGIS项目,命名为“CustomWorkspaceTree”,在该MapGIS插件项目中创建一个IMapContentsView地图视图插件,将Name属性值设为“MapView”,Caption属性值设为“自定义地图视图”;添加一个IDockWindow插件项将Name属性值设为“WorkspaceTree”,Caption属性值设为“自定义工作空间”;添加2个自定义用户控件,设置Name属性值分别为“MapViewCtrl”、“TreeView”;在“MapViewCtrl”自定义控件中拖入一个MapControl地图视图控件,设置MapControl地图视图控件Name属性值为“mapCtrl”;在“TreeView”自定义控件中拖入一个MapWorkSpackTree工作空间树控件,设置MapWorkSpackTree工作空间树控件的Name属性值为“m_tree”;

步骤二:将“MapViewCtrl”自定义控件绑定到“MapView”地图视图插件中,具体实现步骤如下:

(1) 在MapView.cs文件中定义一个自定义用户控件(MapViewCtrl对象)mapViewCtrl 的全局变量;

(2) 修改MapView.cs文件中的ObjecthWnd属性代码如下所示: 程序代码 4 13 修改ObjecthWnd属性代码

       public Control ObjecthWnd
        {
            get { return mapViewCtrl; }
        }

(3) 修改MapView.cs文件中的MapControl属性代码如下所示之后就完成了绑定功能。

程序代码 4 14 修改MapControl属性代码

       public MapGIS.GISControl.MapControl MapControl
        {
            get { return mapViewCtrl. mapCtrl; }
        }

步骤三:将“TreeView”自定义用户控件绑定到“WorkspaceTree”停靠窗口插件项中,具体实现步骤如下。

(1) 在DockWindow.cs文件中定义一个自定义控件(TreeView对象)tree全局变量;

(2) 修改ChildHWND属性字段代码如下所示,即可实现绑定功能:

程序代码 4 15 修改ChildHWND属性字段代码

       public Control ChildHWND
        {
            get { return tree; }
        }

步骤四:在TreeView.cs文件中实现自定义工作空间树的相应功能,实现自定义工作空间具体步骤为:

(1) 定义一个工作空间树控件(MapWorkSpackTree对象)m_tree,添加该树的右键菜 单事件处理,关键代码如下:

程序代码 4 16 TreeView.cs文件中的全局变量

       #region 变量定义
        //工作空间树
        MapWorkSpaceTree m_tree = null;
        //框架对象
        IApplication app = null;
        //地图视图控件
        MapControl mapCtrl = null;
        //地图集合对象
        Maps maps = null;
        #endregion

程序代码 4 17 TreeView自定义控件加载事件代码

    private void TreeView_Load(object sender, EventArgs e)
        {
            try
            {
                //获取框架对象
                app = WorkspaceTree.hk;
                //加载树
                m_tree = new MapWorkSpaceTree();
                m_tree.Dock = DockStyle.Fill;
                //添加到用户控件
                this.Controls.Add(m_tree);

                //注册节点右键菜单单击事件
                m_tree.MenuItemOnClickEvent += new MapGIS.WorkSpaceEngine.MenuItemOnClickHandler(m_tree_MenuItemOnClickEvent);
                m_tree.Document.Title = "地图文档";
            }
            catch(Exception ex){
                MessageBox.Show(ex.ToString());
            }
        }

(2) 实现目录树上的地图节点右键菜单预览地图的功能,在右键菜单单击事件中实现关 键代码如下所示:

程序代码 4 18 mtreeMenuItemOnClickEvent关键代码

       void m_tree_MenuItemOnClickEvent(string typeName, MapGIS.GeoMap.DocumentItem item)
        {
            try
            {
                #region 预览地图
                if (item is Map)
                {
                    Map map = item as Map;
                    //内容视图插件
                    IContentsView icv = null;
                    //获取地图视图                    app.PluginContainer.ContentsViews.TryGetValue(map.Handle.ToString() + "$MapView", out icv);
                    if (icv == null)
                    {
                        //创建自定义地图视图插件
                        icv = app.PluginContainer.CreateContentsView("CustomWorkspaceTree.MapView", map.Handle.ToString() + "$MapView");
                        if (icv != null && icv is IMapContentsView)
                        {
                            IMapContentsView mv = icv as IMapContentsView;
                            //获取地图视图控件
                            mapCtrl = mv.MapControl;
                            //激活地图
                            mv.MapControl.ActiveMap = map;
                            //设置地图显示控件
                            m_tree.WorkSpace.SetMapControl(map, mv.MapControl);
                            //获取地图显示范围
                            Rect rect = map.GetViewRange();
                            if (rect != null && (rect.XMax - rect.XMin).CompareTo(0) > 0 && (rect.YMax - rect.YMin).CompareTo(0) > 0)
                                mv.MapControl.Transformation.SetDispRect(rect);
                            mv.MapControl.Refresh();
                            app.StateManager.OnStateChanged(this, new StateEventArgs());
                        }
                    }
                    else
                    {
                        //如果自定义地图视图插件已经打开
                        IMapContentsView mv = icv as IMapContentsView;
                        if (mv != null)
                        {
                            //激活地图视图
                            app.PluginContainer.ActiveContentsView(mv);
                            Rect rt = map.GetEntireRange();
                            Rect rt1 = map.GetViewRange();
                            mv.MapControl.Refresh();
                        }
                    }
                }
                #endregion
            }
            catch(Exception ex){
                MessageBox.Show(ex.ToString());
            }
        }

步骤五:在地图右键菜单中添加一个自定义菜单,具体步骤为:

(1) 在TreeView.cs文件中定义一个自定义菜单类CustomGloableMenu,该类继承并实 现ISingleMenuItem 接口,具体代码如下:

程序代码 4 19 CustomGloableMenu类中代码

#region 单选右键菜单项类
    class CustomGloableMenu : ISingleMenuItem
    {
        //新建地图文档

        #region ISingleMenuItem 成员
        public bool BeginGroup
        {
            get { return false; }
        }
        public Bitmap Bitmap
        {
            get { return null; }
        }
        public string Caption
        {
            get { return "自定义菜单"; }
        }
        public bool Checked
        {
            get { return false; }
        }
        public bool Enabled
        {
            get { return true; }
        }
        public bool Visible
        {
            get { return true; }
        }
        public void OnClick(DocumentItem item)
        {
            MessageBox.Show("自定义菜单演示!");
        }
        public void OnCreate(MapGIS.WorkSpaceEngine.IWorkSpace ws)
        {
        }
        #endregion
    }
    #endregion

(2) 调用mtree类的WorkSpace属性获取工作空间WorkSpace对象,再调用WorkSpace 对象的GetMenuExtand 方法获取右键菜单项,将返回值传给菜单扩展(IMenuExtander对象)ime;定义一个CustomGloableMenu类对象,并初始化,调用ime对象的AddItem方法将CustomGloableMenu类添加到右键菜单栏中,在DocumentOpenedDocument打开地图文档事件中实现该功能,具体代码如下:

程序代码 4 20 自定义菜单实现具体代码

      void Document_OpenedDocument(object sender, EventArgs e)
        {
            //为地图节点添加右键菜单项
            IMenuExtander ime = this.m_tree.WorkSpace.GetMenuExtand(typeof(MapGIS.GeoMap.Map));
            //自定义菜单对象
            CustomGloableMenu menuItem = new CustomGloableMenu();
            menuItem.OnCreate(this.m_tree.WorkSpace);
            //将自定义菜单添加到右键菜单项
            ime.AddItem(menuItem);
        }

效果如下图所示:

自定义菜单效果图

图 4-9 自定义菜单效果图

步骤五:在MapGIS.AppLoader.exe上面加载完CustomWorkspaceTree.dll这个库后,就可以实现自定义工作空间功能。