视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
基于.NET的插件式GIS应用系统框架设计
2025-10-02 08:06:16 责编:小OO
文档
基于.NET的插件式GIS应用系统框架设计

17792669

1、引言

目前,在笔者所从事的国土行业的大部分GIS管理系统都具有功能类似,业务却不尽相同的特性,为了达到功能上的复用和快速灵活的修改现有程序,加快项目开发进度和效率,必须有稳定的系统框架供项目开发选择。从目前主流的GIS二次开发平台来看,在开发桌面端GIS系统的时候,系统的框架大部分是相同的,这就更需要我们在实际开发中,有一个于GIS开发平台之外的系统架构,来满足不同项目对GIS平台的选择。另外,对于不同的系统目标来讲,用户的操作模式可能也不尽相同。例如,对于侧重数据编辑的系统来讲,注重的是系统编辑方式的便捷性;对于注重数据处理业务的系统来讲,注重的是业务逻辑之间的衔接关系。本文结合作者的实际工作经验,对插件式GIS系统框架设计进行了探讨。

本文首先介绍了插件的原理和实现方法,接着讲述了框架设计的原则和系统架构设计,最后是总结。

2、插件原理及实现

任何一个程序都是由不同的功能模块所组成的,一般在GIS软件中,软件许可都是按照模块来进行定制和收费的。在一些GIS软件及类似软件中,都允许添加用户自定义功能到软件中。在实现的方式上,有些就应用了插件技术,例如ArcGIS软件允许加载自定义的功能动态库(dll文件),并拖放到ArcGIS软件的工具栏上,这就是一种插件技术的应用。插件,既可以是功能按钮,也可以是功能按钮组成的工具栏,甚至可以是自定义的控件。

2.1插件原理

插件是一种遵循统一预定义接口规范编写出来的程序,应用程序在运行时通过接口规范对插件进行调用,以扩展应用程序的功能。插件最典型的例子就是ActiveX控件和COM组件,对插件进行接口管理和调用的应用程序一般称之为宿主程序。不同的软件对自己的功能插件的定义都不尽相同,但原理都一样。正是基于这一点,我们可以在GIS应用程序的开发中定义自己插件。在.NET开发环境下,可以利用反射机制来读取封装在功能模块中的插件。

2.2插件实现

要想在应用程序中实现插件功能,必须解决以下三个问题。第一,插件接口规范的定义,即定义插件;第二,实现插件的加载/卸载,即管理插件;第三,实现插件功能的调用,即调用插件。

1、插件的定义

在实际编码时,可以将插件用接口(interface)来实现,并定义插件规范所必须的一些属性和方法。以下是定义代码:

public interface IPlugCommand

        {       

            //插件功能组名称,相当于工具栏标题

            string CatalogName { get; }

            //插件功能名称,相当于功能按钮名称

            string Name { get; }

            //功能唯一标识码

            string GUID { get; }

            //位图,用于按钮图标的显示

            Bitmap Bitmap { get; }

            //插件功能描述,相当于功能按钮提示符

            string Describe { get; }

            //执行插件功能

            void Excute();

            //插件功能是否满足执行的条件

            bool Enable();

            ///插件功能是否执行完毕

            bool Finish();

    }

2、插件管理

(1)插件功能组定义

public interface IPlugCommandGroup

        {

            //插件组名称,相当于工具栏名称

            string Name { get; }

            //插件功能个数

            int CommandCount { get; }

            //插件路径

            string PathName { get; }

            //按序号获取插件

            IPlugCommand GetCommandAt(int index);

            /// 根据插件唯一标识guid查找插件      

            IPlugCommand FindCommandByGUID(string guid);

            /// 根据插件名称查找插件        

            IPlugCommand FindCommandByCommandName(string commandName);

            /// 根据插件唯一标识guid值删除命令

            bool RemoveCommandByGUID(string guid);

            /// 卸载所有插件

            void RemoveAllCommand();

            // 添加插件

            bool AddCommand(IPlugCommand command);

            /// 装载插件

            bool LoadCommand(string strPath);

    }

(2)插件管理器定义

public interface IPlugCommandManager

{

///功能组个数

            int GroupCount { get; }

            ///添加功能组

            bool AddGroupCommand(IPlugCommandGroup commandGroup);

            ///卸载功能组

            bool RemoveGroupCommand(string groupName);

            ///根据功能组序号获取功能组

            IPlugCommandGroup GetCommandGroupAt(int index);

            /// 根据功能组名称查找功能组

            IPlugCommandGroup FindGroupCommand(string groupName);

            /// 根据插件唯一guid值查找插件

            IPlugCommand FindCommandByGUID(string guis);

            /// 从配置文件读取要加载的插件路径并加载插件

            bool LoadFromXMLFile(string strFileName);

            /// 将插件路径写入配置文件

            bool WriteToXMLFile(string strFileName);

    }

3、插件的实例化及调用

(1)插件的实例化

插件的实例化可以采用.NET的反射机制进行读取和实例化,实例化代码如下:

//根据插件实力化名称和插件名称创建插件

private  IPlugCommand LoadObject(string className, string interfaceName, object[] param)        

        {

            Type t = Type.GetType(className);

            if (t == null || !t.IsClass || !t.IsPublic || t.IsAbstract 

|| t.GetInterface(interfaceName) == null)

            {

                return null;

            }

            object obj = Activator.CreateInstance(t, param);

            return (IPlugCommand) obj;           

        }

        //加载给定路径的插件

        public bool LoadCommand(string strPath)

        {            

            // 获取插件接口名称

            string interfaceName = typeof(IPlugCommand).FullName;

            // 载入插件文件

            Assembly asm = Assembly.LoadFile(strPath);

            if (asm == null)

            {

                return false;

            }

            foreach (Type t in asm.GetExportedTypes())

            {               

                // 载入插件,如果插件不符合指定的接口,则返回null

                IPlugCommand plugin = LoadObject(t.AssemblyQualifiedName, interfaceName, null);

                if (plugin != null)

                {

                    //将插件加入插件组

                    AddCommand(plugin);

                }

            }

        }

(2)插件的调用

当应用程序加载了插件以后,会自动生成插件对应的工具条和工具按钮,并将插件的唯一标识guid存储到功能按钮的属性中,当用户在界面上点击功能按钮时,在从属性中读取功能按钮的唯一标识guid,并根据该guid在插件管理器中查询到该插件,并调用插件的执行函数即可。

3、插件式GIS应用系统框架的设计原则

为了增加插件式GIS系统框架的柔韧性和灵活性,笔者尽量按照一定的原则去设计系统,在实际工作中,主要遵从以下几个原则:

1、GIS平台无关性

在国土信息化建设的过程中,制定总体解决方案时往往包含一系列的系统,如数据管理系统,辅助决策支持系统、督查巡查系统、电子政务系统,在信息化逐步实施的过程中,往往就决定了系统所采用的GIS二次开发平台,这就决定了项目实施方必须具备多个GIS平台的应用系统开发的能力。为了达到程序资源的最大化利用,插件式GIS框架的定义和实现需要具备与平台无关的特性,具体到某个GIS平台的二次开发时,只需要实现插件式GIS框架所规定的接口即可。

2、业务模块的低耦合性

每一个业务系统,都有系统相关的特定资源,这样就要求GIS应用系统的框架需要与具体的业务剥离开来,我们在针对某一具体的应用领域开发应用系统时,都可以基于该框架延伸出新的应用系统框架。例如当侧重于数据的编辑时,可以加入编辑所需要的系统环境,生成数据编辑处理系统框架;当侧重于数据管理时,可加入数据管理所需要的系统登录信息、数据存储信息等系统资源的初始化功能,生成数据管理系统框架;当实时处理督查巡查相关业务数据的时候,也可以加入督查巡查业务所需要的资源环境,生成督查巡查业务系统框架。

3、用户操作模式的统一性

不同的GIS软件,对于用户操作的模式是不一样的,二次开发时改变当前操作的方式也不一样。所以框架需要封装不同GIS软件的操作模式,反映出统一的用户操作体验。同时为了封装用户和界面的交互,需要提供一系列的对象供开发插件时使用。这样使得功能开发时,开发人员只需要利用框架提供的对象实现功能要素(空间对象,用户输入值等)的获取,而不必关心系统表现的形式。

4、插件式GIS系统框架的架构设计

基于上述的设计原则,笔者所实现的插件式GIS应用系统架构如下图所示:

架构设计采用分层架构的模式,共分为5层。最底层是应用程序框架定义层,接着是操作定义层,然后是框架视图和用户操作的实现层,第二层是业务组件和功能插件层,最上层是系统应用层。

4.1框架定义层

框架定义层是与GIS平台无关的层,主要实现系统框架的定义,主要包含插件定义和实现模块、插件管理和实现模块、视图定义模块以及框架定义模块,各部分功能描述如下:

插件定义和实现模块:实现插件接口的方法和属性定义,以及公共实现接口和方法类。

插件管理和实现模块:实现插件管理器接口的方法和属性定义以及实现类。

视图定义模块:实现各种应用视图的定义,包括地图窗口、打印窗口、属性窗口、图层记录集窗口等等。

框架定义模块:实现和系统应用框架接口定义,主要包括管理用户界面资源的接口和管理应用相关环境变量的接口。

4.2操作定义层

操作定义层是与具体GIS平台无关的层,实现各种操作定义模块和核心函数,主要功能模块描述如下:

操作定义模块:实现操作接口的定义,如获取地图点坐标,获取用户选择要素等一系列的操作定义。

核心函数模块:实现一些和GIS操作无关的核心函数,如解析求点,求两点之间角度等函数。

核心命令模块:实现一些GIS扩充命令的接口,以便在实现gis操作时重载。

草图绘制定义模块:实现地图草图绘制接口的属性和方法定义,主要用于用户在地图窗口绘制和修改要素时的草图(橡皮线)绘制。

4.3框架视图和用户操作实现层

框架视图和用户操作实现层适合具体GIS相关的逻辑层,系统采用什么样的GIS平台,只需要用该平台的二次开发组件实现相应接口功能即可,主要功能模块描述如下:

地图窗口控件模块:实现框架定义层定义的地图窗口接口,用于GIS数据的显示。

图层管理控件模块:实现框架定义层定义的图层管理接口,主要用于管理地图窗口中显示的GIS数据,包括图层数据的调整,图层属性编辑等。

记录集窗口控件模块:实现框架定义层定义的记录集窗口接口,主要用于显示某个图层所有的记录或者地图窗口选择的记录信息。

属性窗口控件:实现框架定义层定义的属性窗口接口,主要用于显示和编辑图形对象的坐标信息和属性信息。

专题图窗口控件:实现框架定义层定义的专题图窗口接口,主要用于地图专题图目录的显示和专题图的加载等功能。

操作实现函数模块:实现操作定义层定义的各种操作。

草图绘制实现模块:利用GIS组件实现草图的绘制功能。

核心函数模块:实现GIS操作所需要的核心函数。

4.4业务组件和功能插件层

业务组件层和功能插件层是实现具体业务功能和插件功能的逻辑层,该层主要根据不同的业务特征来实现,GIS应用系统的类型的本质区别就体现在这一层。主要模块功能描述如下:

业务功能实现模块:实现业务功能对象,为功能插件所调用。

业务功能环境定义和实现模块:实现业务环境接口定义以及功能实现类。

插件功能模块:按照插件原理实现功能插件。

4.5系统应用层

系统应用层属于用户界面交互层,主要包括底层框架定义的实现和系统主界面,是各种GIS系统共用的逻辑层。

5、总结

本文详细的介绍了插件原理和插件式GIS应用系统架构的设计,但是对于具体的实现没有过多描述,关于如何运用不同的GIS平台开发组件进行应用系统的开发不是本文的重点,也非三言两语能够表述清楚。本文仅试图将插件原理如何应用到GIS应用系统的开发做具体描述,并基于笔者的实际经验,将基于笔者愿景的插件式GIS应用系统架构描述清楚。

对于不同的GIS开发平台,由于其开发方式和系统特性的不同,在系统框架的具体实现上会有不同,但是具体的思想和系统架构是相同的,这也是框架设计的初衷之一。同时,在实际开发过程中,也会用到其他的诸如多线程,线程异步调用,XML文件读写等技术,在此也没有一一描述。

如下图所示,上图为基于ArcGIS二次开发包ArcEngine开发出的土地调查数据更新工具软件,下图为基于SuperMap Objects开发的数据编辑系统原型。两者都是在基于文中提到的架构设计的基础上实现的GIS应用系统,只需要加载不同的业务组件和功能插件层,就能组成一个新的应用系统。

实例一  基于ESRI公司ArcEngine开发的土地调查数据更新工具软件

实例二 基于超图SuperMap Objects开发的编辑系统原型下载本文

显示全文
专题