95992828九五至尊2

框架的筹划与达成,串口和网络

二月 5th, 2019  |  882828九五至尊手机版

目       录

目       录

第七章           外部接口的设计… 2

第十章           宿主程序详细设计… 2

7.1           插件接口… 2

10.1        配置文件设计… 3

7.2           图形突显接口… 3

10.2        加载设备驱动… 4

7.3           数据导出接口… 5

10.3        加载界面视图… 8

7.4           服务组件接口… 6

10.4        加载数据导出… 12

7.5           插件管理器… 8

10.5        加载服务组件… 14

7.6           框架整合、重构… 9

10.6        全局格外监测… 17

7.7           小结… 10

10.7        小结… 19

第七章     外部接口的设计

开发者不仅可以二次开发设备驱动,还是可以二次开发自定义图形突显格局、

自定义数据导出格式和多样业务服务,并且配备驱动接口与那两种接口进行事件响应和多少交互。

 

7.1    插件接口

   
图形显示接口、数据导出接口和劳动组件接口都持续自统一的插件接口(IPlugins),紧假使方便管理和增加。插件接口的代码定义如下:

public interface IPlugins : IDisposable
{
       /// <summary>
       /// 服务Key,要求唯一
       /// </summary>
       string ThisKey { get; }

       /// <summary>
       /// 服务名称
       /// </summary>
       string ThisName { get; }

       /// <summary>
       /// 更新设备数据,用于接收来自设备驱动的数据信息
       /// </summary>
       /// <param name="devid">设备ID</param>
       /// <param name="obj">设备对象</param>
       void UpdateDevice(int devid, object obj);

       /// <summary>
       /// 移除设备,当框架平台删除设备的时候进行响应。
       /// </summary>
       /// <param name="devid">设备ID</param>
       void RemoveDevice(int devid);
}

    
图形突显接口、数据导出接口和劳动组件接口与插件接口的后续关系如下图:

图片 1 

    
设备驱动只要有更新数据就会通过事件把数量传送到UpdateDevice接口里,那几个接口内部到底怎么处理完全由二次开发者来控制。当接触设备驱动的删减事件,就会调用RemoveDevice接口,以删除、释放资源。

第十章     宿主程序详细安顿

    
前几章对设备驱动、IO实例、外部接口和一体化控制器等展开了详实介绍,那一个都是框架平台的有机组成部分,这一部分一定于后台服务的支撑组件,通过模块化已毕框架平台的搭建;宿主程序也是框架平台的一部分,作为承载插件的一个软件平台,是人机交互的绝无仅有接口,通过鼠标点击完结各个指令,是插件式框架平台最终要落到实处的一部分。在《第2章
框架总体的统筹》的“2.1
宿主程序设计”中对宿主程序的一体化机能和界面举办了设计和筹划,不过并从未涉及到细节层面,要贯彻那一个安排的机能,包含3地方工作:界面的兑现,也就是UI布局,涉及到少量的代码控制;与插件(设备驱动、图形突显、数据导出和劳务组件)进行相互,把必要的插件加载到宿主程序中,最终传递给后台服务;与《第8章
总体控制器的统筹》中的IDeviceController总控制器接口举办互动,可以清楚为与后台服务的协理组件进行交互,接收宿主程序的输入,一般为插件音信、操作响应等。交互的布局示意图如下:

图片 2 

   
宿主程序接受来自人员的动作,通过布署文件落成加载插件或者把已经加载的插件与总控器进行交互。当然,宿主程序也恐怕与其余支持工作进行互动。

7.2    图形呈现接口

   
框架平台通信设备驱动把多少搜集上来的只是土生土长数据,经过处理后要形成工作数据,那么就会有显示、分析、查询、打印、报表等业务作用,并且针对同一的数额新闻,不相同的用户须求处理的点子有很大的分化。那有些效能转移很大,可是又不能够每一次有变动就要去修改框架平台,因为框架是“稳定”的片段,形成版本控制后就不随便更改了。

  
基于那样考虑,作为框架要提供一个体制,可以加载二次开发者设计的UI窗体。用于展现采集终端设备的多少,可以把不一致门类设备的多寡以二种方式集成突显在分化界面上。方便为用户提供各种的、更温馨的人机交互界面。

  
首先,框架平台无法在启动的时候就显示所有UI窗体,具体要来得哪个UI窗体完全由用户自己控制,所以,大家要经过安顿文件的款型把二次开发的组件音讯加载到菜单里,提供可触及的体现事件入口,如下图:

图片 3 

   其次,那么以如何的方式显得窗体呢?像许多管制连串一样,大家应用Form
Tab的主意显示,如下图:

 图片 4

  
UI部分的布署性就这样了,然而从作业角度大家要考虑两件事:(1)在二次开发的窗体上单击鼠标右键事件时要突显相应设施的上下文菜单,也就是说要调用IRunDevice设备驱动的ShowContextMenu函数,要在IGraphicsShow接口中提供MouseRightContextMenuHandler事件,以使得调用ShowContextMenu函数呈现上下文菜单。(2)当单击菜单项的时候,会以Tab的款型显示窗体,不过当多次单击后是不能反复展现UI窗体的,所以要有一个管理器(GraphicsShowController),通过接口的ThisKey属性判断当前呈现的UI窗体是还是不是存在,如果不设有,那么就浮现该UI窗体,否则退出操作;既然有一个管理器,当关闭窗体的时候,要求把该UI窗体实例从管理器中剔除掉,避免不能再度突显窗体,因为它一向留存于管理器中。所以还须求在接口中定义一个关闭窗体的风云GraphicsShowClosedHandler,释放窗体资源后从管理器中删除实例。

   至此,自定义窗体显示部分就筹划落成了,IGraphicsShow接口定义代码如下:

public interface IGraphicsShow : IPlugins
{
       /// <summary>
       ///    关闭窗体事件时发生
       /// </summary>
       event GraphicsShowClosedHandler GraphicsShowClosedHandler;

       /// <summary>
       ///     单击右键
       /// </summary>
       event MouseRightContextMenuHandler MouseRightContextMenuHandler;
}

10.1     配置文件设计

      
加载插件的主意有很多样,可以由此遍历指定目录下的程序集,找到呼应的插件接口类型,并且加载到框架平台,现在有不少编纂软件都是利用的如此形式。但是自己深感这种措施有些有些暴力,不可能任什么人来到你家门前就同意他进门的。所以,SuperIO框架平台拔取一种更温馨的法子,通过配备文件加载插件。把二次开发好的插件音信配置到相应的文件中,唯有插件新闻“合法”的场所下才会根据事态加载插件到框架平莱比锡。

据悉那样考虑,就必要对计划文件举办设计,以如何的文件格式保存新闻,以及都保存什么样的音讯。

      配置文件的格式拔取XML情势,对.NET
Framework的System.Configuration.Configuration工具类举行二次封装。先定义一个接口,对操作配置文件举办专业,接口定义如下图:

图片 5 

    
配置文件保留什么样的新闻,取决于应用进程中所须求的新闻,差其余插件可能用到的配备音信不相同。那么先定义一个基础的安顿音讯,包罗:插件文件路径、实例类音讯(命令空间和类名)、标题和标注等信息,以便可以透过反射工具类加载插件。配置音信类定义如下图:

图片 6 

    使用布署文件操作基类生成的文件格式如下图:

图片 7

7.3    数据导出接口

   
在数量集成系统项目中,要么是合二为一其他厂家的配备数据,要么是其他厂家集成自己家的装备数量,在并未统一的专业前提下,会有种种集成数据的格式。为了满足此类的气象,为装备导出数据专门计划了接口,开发者可以接二连三该接口,设备在拍卖完数据后,会把数据自动传输到该接口,可以按规定的多寡格式举行输出了。

     对配备驱动实时数据导出,可以把一类的装置数据导出成三种数目格式。

    
导出多少插件可以经过配备文件举行加载,只要设备驱动有数据更新,就把数量经过事件传递给导出数据接口。不在配置文件中安插插件音讯,则程序不进行加载,不开展导出操作。所以,这种事务性的劳务不必要界面来形成,可以在宿主程序启动时通过代码来完结。

    IExportData数据导出接口代码定义如下:

public interface IExportData:IPlugins
{
       /// <summary>
       /// 格式化数据
       /// </summary>
       /// <param name="devid"></param>
       /// <param name="obj"></param>
       /// <returns></returns>
       object FormatDataString(int devid, object obj, DeviceType devicetype);
}

10.2     加载设备驱动

    
设备驱动的布署文件与功底配置文件不一样,主要涉及到两有些:可挂载的配备驱动音讯和已经挂载到框架平台的驱动新闻。

    
可挂载的设施驱动新闻在AssemblyDeviceSectionGroup配置组中展开布置,当挂载新的装置驱动的时候,如扩张设备,就会从那个配置组中加载新闻,以便操作人员展开精选。配置组下的设施驱动配置音信定义如下图:

图片 8 

    当调用扩充设备窗体的时候会从配置文件读取程序集新闻,如下图:

图片 9 

    当触发增加设备事件的时候,会成立新的设备驱动,代码完毕如下:

public static IRunDevice CreateDeviceInstance(int devid, int devaddr, string devname, int assemblyid, string assemblyname, string instance, CommunicationType type, DeviceType devType, object iopara1, object iopara2)
{
       IObjectBuilder builder = new TypeCreator();
       IRunDevice dev = builder.BuildUp<IRunDevice>(Application.StartupPath + "\\SuperIO\\DeviceConfig\\" + assemblyname, instance);
       dev.DeviceParameter.DeviceAddr = devaddr;
       dev.DeviceParameter.DeviceName = devname;
       dev.DeviceRealTimeData.DeviceName = devname;
       if (type == CommunicationType.COM)
       {
              dev.DeviceParameter.COM.Port = (int)iopara1;
              dev.DeviceParameter.COM.Baud = (int)iopara2;
       }
       else if (type == CommunicationType.NET)
       {
              dev.DeviceParameter.NET.RemoteIP = (string)iopara1;
              dev.DeviceParameter.NET.RemotePort = (int)iopara2;
       }
       dev.IsRegLicense = true;
       dev.CommunicationType = type;
       dev.UserLevel = UserLevel.High;
       dev.InitDevice(devid);
       if (!Device.DebugDevice.IsDebug)
       {
              //--------------------把设备信息配制到文件中------------------------//
              CurrentDeviceSection section = new CurrentDeviceSection();
              section.DeviceID = dev.DeviceParameter.DeviceID;
              section.AssemblyID = assemblyid;
              section.X = 0;
              section.Y = 0;
              section.Note = String.Empty;
              section.CommunicateType = dev.CommunicationType;
              DeviceAssembly.AddDeviceToXml(section);
              //---------------------------------------------------------------//
       }
       return dev;
}

     
已经挂载到框架平台的驱动新闻在CurrentDeviceSectionGroup配置组中进行配置,也就是对已经挂载的装备驱动,在下次启动框架平台的时候要活动把这么些设备驱动挂载到平台下运作,当爆发删除设备驱动事件时从该配置组中去除相关音信。可以设置通信类型变更设备驱动的简报形式。配置组下的配制音讯定义如下图:

图片 10 

  
当下次启动框架平台时会从这一个配置组加载并实例化设备驱动,挂载到框架平台下运作设备驱动实例,在宿主程序中显得设备驱动实例实时运行状态。加载设备驱动代码如下:

public static List<IRunDevice> LoadDevicesFromXml()
{
       List<IRunDevice> list = new List<IRunDevice>();
       CurrentDeviceSectionGroup curgroup = (CurrentDeviceSectionGroup)_Source.Configuration.GetSectionGroup("CurrentDeviceSectionGroup");
       if (curgroup == null)
       {
              throw new NullReferenceException("获得当前设备配置信息为空");
       }
       AssemblyDeviceSectionGroup asmgroup = (AssemblyDeviceSectionGroup)_Source.Configuration.GetSectionGroup("AssemblyDeviceSectionGroup");
       if (asmgroup == null)
       {
              throw new NullReferenceException("获得设备程序集信息为空");
       }
       IObjectBuilder creator = new TypeCreator();
       for (int i = 0; i < curgroup.Sections.Count; i++)
       {
              CurrentDeviceSection cursect = (CurrentDeviceSection)curgroup.Sections[i];
              if (cursect.AssemblyID >= 0)
              {
                     for (int j = 0; j < asmgroup.Sections.Count; j++)
                     {
                            AssemblyDeviceSection asmsect = (AssemblyDeviceSection)asmgroup.Sections[j];
                            if (cursect.AssemblyID == asmsect.AssemblyID)
                            {
                                   string assemblypath = Application.StartupPath + "\\SuperIO\\DeviceConfig\\" + asmsect.AssemblyName;
                                   IRunDevice dev = creator.BuildUp<IRunDevice>(assemblypath, asmsect.Instance);
                                   dev.InitDevice(cursect.DeviceID);
                                   dev.CommunicationType = cursect.CommunicateType;
                                   list.Add(dev);
                                   break;
                            }
                     }
              }
       }
       return list;
}

     设备驱动全部安插文件如下图:

图片 11

7.4    服务组件接口

    
围绕着设备驱动模块采集的数额,按照应用场、要求,可以提供三种应用服务,例如:数据转载服务、4-20mA服务、短信服务、LED服务、OPC服务、以及错综复杂的实时数据解析服务等。在维周密据实时性、稳定性的前提下,服务接口可以提供统一的劳动体制,方便开发者举办二次开发。

    
服务插件的劳务章程,那种劳动是绵绵运行的事务性职务,所以更扑朔迷离一些。

   
有些服务需求随宿主程序启动而机关运行,有些服务要求人工手动启动才运行。在宿主程序启动的时候经过配制文件要把服务的信息加载到菜单上,菜单里显示的劳务或者有些已经起步了;有些须要经过单击操作,呈现窗体并填写须求的音信后才可能启动。所以,宿主程序与劳动插件不是单向交互,而是双向数据、事件交互。

   
IappService服务接口在IPlugins基础上进展伸张,增添了函数、属性和事件,代码定义如下:

public interface IAppService : IPlugins
{
        /// <summary>
       ///     启动服务
       /// </summary>
       void StartService();

       /// <summary>
       ///     是否自动启动
       /// </summary>
       bool IsAutoStart { set; get; }

         /// <summary>
       ///     服务类型
       /// </summary>
       ServiceType ServiceType { set; get; }

       /// <summary>
       ///     单击事件,关联菜单
       /// </summary>
       void OnClick();

       /// <summary>
       ///     释放服务
       /// </summary>
       void ReleaseService();

       /// <summary>
       ///     写日志事件
       /// </summary>
       event WriteLogHandler WriteLogHandler;
}

(1)   
StartService函数:当服务的开行格局(IsAutoStart)为”自动启动”的时候,框架平台在加载服务的时候,会活动调用那几个接口函数,表示对劳务拓展启动操作。

(2)   
IsAutoStart属性:服务启动项目,标识是不是随框架平台启动而活动启动,也就是标识是还是不是会调用StartService接口函数。

(3)   
ServiceType属性:服务类型分为:展现方式和隐身方式。呈现情势的服务会在框架平台的菜谱上加载以ThisName标识的劳务名称;隐藏情势不会在框架平台的菜系中加载服务名称,能够把该类服务的IsAutoStart属性设置为自发性启动,框架平台启动后自动启动服务。代码定义如下:

public enum ServiceType
{
    [EnumDescription("显示模式")]
    Show = 0x00,
    [EnumDescription("隐藏模式")]
    Hide = 0x01
}

(4)   
OnClick事件函数:当服务类型ServiceType为“突显情势“的时候,服务名称会被加载到菜单中,当单击服务菜单项的时候,会调用相应服务的OnClick接口函数,可以在这几个接口函数里调用窗体。

(5)   
ReleaseService函数:当关闭框架平台和人为手动为止服务后,可以经过那一个函数释放服务资源。

 别的,对于服务组件接口还论及到劳动场馆,标识服务在运转的进度中处

于怎么样阶段,例如:服务正在起步、服务已经启动、服务正在运作、服务正在终止、服务业已告一段落等等。因为依据劳动的业务复杂度不相同,服务的情事也恐怕两样,所以服务场馆的定义交给了二次开发者自己定义。

10.3     加载界面视图

   
组态软件会有一个图形和UI引擎来辅助图形数字化展现,允许二次开发者通过拖拽UI组件进行图形化设计,并设置UI组件的习性与IO变量举行关联来呈现数据音信。

   
考虑到开发费用和人报酬本,SuperIO没有像组态软件的方法贯彻图形化呈现,可是自定义图形化UI突显部分是必须贯彻的,知足分化用户、不相同采用场景的要求。

   
SuperIO是由此事件和接口的格局来贯彻自定义图形呈现。设备驱动对数码举办包装,打包后的多少可能是:字符串(数组)、类对象、字节数组等,通过调用事件(OnDeviceObjectChangedHandler)把包裹后的数量以目的的花样传递给图形突显接口(IGraphicsShow),再反向解析数据音讯浮现在不一样的UI组件上,帮助多样突显风格。

    
那么,那样就帮衬二次开发者继承图形显示接口(IGraphicsShow),独立开发一个零部件(DLL),并且挂载到布署文件中,当鼠标单事菜单的图样突显项时自动以插件的样式加载DLL,并以FormTab的格局突显图形界面。

   
针对加载界面视图的凡事经过涉及到:配制文件、加载视图菜单、单击事件突显视图等。

    配置文件与功底配置文件一律,配置文件定义如下图:

 图片 12

    
当框架平台启动时,会自行加载配置文件,并出示在界面视图的食谱中,加载配置文件的代码如下:

private void LoadShowView()
{
       IConfigurationSource source = new SuperIO.ShowConfiguration.ShowConfigurationSource();
       source.Load();
       for (int i = 0; i < source.Configuration.SectionGroups.Count; i++)
       {
              if (source.Configuration.SectionGroups[i].GetType() == typeof(SuperIO.ShowConfiguration.ShowSectionGroup))
              {
                     SuperIO.ShowConfiguration.ShowSectionGroup group = (SuperIO.ShowConfiguration.ShowSectionGroup)source.Configuration.SectionGroups[i]
                     Font font = new Font("Tahoma", 12);
                     SuperIO.ShowConfiguration.ShowSection section=null;
                     for (int j = 0; j < group.Sections.Count; j++)
                     {
                            section = (SuperIO.ShowConfiguration.ShowSection)group.Sections[j];
                            BarButtonItem bt = new BarButtonItem(this.barManager1, section.Caption);
                            bt.ItemAppearance.SetFont(font);
                            bt.Tag = section.Name + "," + section.Instance + "," + section.Caption;
                            bt.ItemClick += new ItemClickEventHandler(ViewItem_ItemClick);
                            barGraphicsView.AddItem(bt);
                     }
                     break;
              }
       }
}

    
当鼠标单击菜单项时会触发ViewItem_ItemClick函数,并加载、展现视图界面,定义的代码如下:

private void ViewItem_ItemClick(object sender, ItemClickEventArgs e)
{
       try
       {
              string[] arr = e.Item.Tag.ToString().Split(',');
              SuperIO.ShowConfiguration.ShowConfigurationSource source = new SuperIO.ShowConfiguration.ShowConfigurationSource();
              IObjectBuilder builder = new TypeCreator();
              Form form = builder.BuildUp<Form>(Application.StartupPath + "\\SuperIO\\ShowConfig\\" + arr[0], arr[1]);
              if (this._DeviceController.AddGraphicsShow((IGraphicsShow)form))
              {
                     form.Text = arr[2].ToString();
                     form.MdiParent = this;
                     form.Show();
              }
              else
              {
                     form.Dispose();
              }
       }
       catch (System.Exception ex)
       {
              MessageBox.Show(ex.Message);
       }
}

  
在这一个进度中,有一个标题考虑到,就是累累单击同一个菜系视图项时,不可能屡屡显得同一个界面视图窗体,首要考虑到统筹的创制和实践的频率。_DeviceController.AddGraphicsShow((IGraphicsShow)form)函数的代码定义如下:

public bool AddGraphicsShow(IGraphicsShow graphicsShow)
{
       if (!_dataShowController.Contain(graphicsShow.ThisKey))
       {
              _dataShowController.Add(graphicsShow.ThisKey, graphicsShow);
              graphicsShow.MouseRightContextMenuHandler += new MouseRightContextMenuHandler(RunContainer_MouseRightContextMenuHandler);
              graphicsShow.GraphicsShowClosedHandler+=new GraphicsShowClosedHandler (GraphicsShow_GraphicsShowClosedHandler);
              DeviceMonitorLog.WriteLog(String.Format("<{0}>显示视图已经打开", graphicsShow.ThisName));
              return true;
       }
       else
       {
              DeviceMonitorLog.WriteLog(String.Format("<{0}>显示视图已经存在", graphicsShow.ThisName));
              return false;
       }
}

7.5    插件管理器

   
图形突显接口、数据导出接口和服务组件接口都各自有一个接口管理器,负责对各职能接口举办保管,它们都继承自IBaseManager<TKey,
TValue>接口。继承关系图如下:

 图片 13

10.4     加载数据导出

   
一般景色下用不到多少导出插件接口成效,可是在做项目标时候的确会生出二种多少格式举行交互的气象,例如:N个厂家要合并自己的数量新闻,但是规定的数目格式又不雷同,又迫于用户的要挟,不得不合作工作。那么就足以用数码导出插件来完结。

    
有人会猜忌:那样的职能否够在配备驱动和浮现视图中落成吗?当然可以如此操作。可是,我不想把开发稳定的设备驱动和浮现视图作用模块随意增添代码,更不情愿为了本来不相干的事情可能影响到自然应该干好的事体,对于有“洁癖”的开发者来讲更不愿意那样干。本来设备驱动在框架平马普托就是可变的因数,不过对于数据导出又是周旋稳定性的一些,所以把数量导出作用重新解耦出来,单独设计成插件组件的主意。

   
这一部分功用设计的比较不难,也是通过计划文件的法子挂载插件,每回启动框架平台都会把计划文件中的数据导出插件加载进来,直到框架平台退出。也就是说挂载相应的插件就有相应的导出数据功用,不加载插件就不会有其他操作。

    配置文件与功底配置文件一律,配置文件定义如下图:

 图片 14

    加载插件的代码定义如下:

public static List<IExportData> GetExportInstances()
{
       List<IExportData> exportlist = new List<IExportData>();
       ExportConfigurationSource source = new ExportConfigurationSource();
       source.Load();
       ExportSectionGroup group = (ExportSectionGroup)source.Configuration.GetSectionGroup("Export");
       if (group == null)
       {
              throw new NullReferenceException("获得导出程序集信息为空");
       }

       IObjectBuilder builder = new TypeCreator();
       foreach (ExportSection section in group.Sections)
       {
              IExportData export = builder.BuildUp<IExportData>(Application.StartupPath+ "\\SuperIO\\ExportConfig\\" + section.Name, section.Instance);
              exportlist.Add(export);
       }
       return exportlist;
}

7.6    框架整合、重构

   
总的来说,框架平台涉及到八个第一的接口:IRunDevice设备驱动接口、IGraphicsShow图形突显接口、IExportData数据导出接口和IAppService服务组件接口。它们现在的继承结构关系如下图:

图片 15 

实际上继承那多少个接口二次开发的模块都是以插件的情势加载到框架平台,框架平台在结构上达成了一整套的运行机制。对地点的接续关系结构图举办解析,还有整合、重构的余地,进一步明晰接口关系、整合代码,提升框架的可增加性,安顿重构后的接口继承关系如下图:

图片 16 

    
所有可扩展的接口都延续自一个插件接口,再分支出来其他的业务成效接口,类似于C#语言中负有实体都一而再自Object一样。

10.5     加载服务组件

    
设备驱动的效应只负责与硬件装备开展互相,不可以把事务性的劳动加到设备驱动中,否则恐怕会潜移默化多少正常的交互;界面视图只负责对采访上来的数额开展实时呈现,不可能把事务性的服务加到界面视图中,否则会潜移默化人机交互的体验感;数据导出只担负对数码举行格式化并导出到相应的介质中,无法把事务性的服务加到数据导出中,否则数据导出不负有效率界面的交互能力。

    
服务组件针对卓绝的事务性服务场合,请参见《7.外部接口的安顿》。服务组件的加载进度与界面视图的加载进度看似。

安顿文件与基础配置文件一律,配置文件定义如下图:

图片 17

   
当框架平台启动时,会自行加载配置文件,并出示在劳务的食谱中,加载配置文件的代码如下:

private void LoadServices()
{
       IConfigurationSource source = new SuperIO.ServicesConfiguration.ServicesConfigurationSource();
       source.Load();
       List<IAppService> serviceList = new List<IAppService>();
       for (int i = 0; i < source.Configuration.SectionGroups.Count; i++)
       {
              if (source.Configuration.SectionGroups[i].GetType() == typeof(SuperIO.ServicesConfiguration.ServicesSectionGroup))
              {
                     IObjectBuilder builder = new TypeCreator();
                     SuperIO.ServicesConfiguration.ServicesSectionGroup group = (SuperIO.ServicesConfiguration.ServicesSectionGroup)source.Configuration.SectionGroups[i];
                     Font font = new Font("Tahoma", 12);
                     SuperIO.ServicesConfiguration.ServicesSection section=null;
                     for (int j = 0; j < group.Sections.Count; j++)
                     {
                            section = (SuperIO.ServicesConfiguration.ServicesSection)group.Sections[j];
                            IAppService appService = builder.BuildUp<IAppService>(Application.StartupPath + "\\SuperIO\\ServicesConfig\\" + section.Name, section.Instance);
                            appService.ServiceType = section.ServiceType;
                            appService.IsAutoStart = section.IsAutoStart;
                            serviceList.Add (appService);
                            if (section.ServiceType == ServiceType.Show)
                            {
                                   BarButtonItem bt = new BarButtonItem(this.barManager1, section.Caption);
                                   bt.ItemAppearance.SetFont(font);
                                   bt.Tag = appService.ThisKey;
                                   bt.ItemClick += new ItemClickEventHandler(ServiceItem_ItemClick);
                                   barServices.AddItem(bt);
                            }
                     }
                     break;
              }
       }
       _DeviceController.AddAppService(serviceList);
}

    
_DeviceController.AddAppService(serviceList)代码会把服务插件的实例扩展到控制器中,代码如下:

public void AddAppService(List<IAppService> serviceList)
{
       foreach (IAppService service in serviceList)
       {
              if (!_appServiceManager.Contain(service.ThisKey))
              {
                     service.WriteLogHandler += new WriteLogHandler(Service_WriteLogHandler);
                     if (service.IsAutoStart)
                     {
                            service.StartService();
                     }
                     _appServiceManager.Add(service.ThisKey, service);
                     DeviceMonitorLog.WriteLog(String.Format("<{0}>应用服务已经打开", service.ThisName));

              }
              else
              {
                     DeviceMonitorLog.WriteLog(String.Format("<{0}>应用服务已经存在", service.ThisName));
              }
       }
}

  
当单击菜单服务项时会调用ServiceItem_ItemClick函数,会调用服务组件的单击事件函数,代码如下:

public void OnClickAppService(string key)
{
       IAppService service = _appServiceManager.Get(key);
       if (service != null)
       {
           service.OnClick();
        }
}

7.7    小结

   
框架之中实际上是对接口举办直接调用,接口与接口之间的格外又已毕了一套协调机制,从而逐步完成了一个框架平台。作为接口实际上是贯彻了二次开发与框架平台对接的一种样式,并保管在框架平台的调和机制中贯彻特定的事情职能。所以,任何框架,从顶层来看都是对接口的安顿性。

 

小编:唯笑志在

mail:504547114@qq.com

QQ:504547114

.NET开发技术联盟:54256083

文档下载:http://pan.baidu.com/s/1pJ7lZWf

法定网址:http://www.bmpj.net

10.6     全局格外监测

    
框架平台的风平浪静始终是非同一般,在运转进程中或者爆发任何未知非凡音讯,针对这么些更加是力不从心用早已存在的try…catch…来捕捉的。

    
在开行框架平台的时候扩张了ThreadException和UnhandledException事件对未知极度举行捕捉,并把事件中对格外新闻举行详尽的笔录。

     ThreadException事件,此事件允许 Windows 窗体应用程序处理 Windows
窗体线程中所暴发的别样未经处理的百般。 请将事件处理程序附加到
ThreadException
事件以处理那几个更加,因为这么些特别将使你的应用程序处于未知状态。
应竭尽拔取结构化非凡处理块来处理非凡。详情请参见MSDN。

     UnhandledException事件,此事件提供未捕获到的相当的关照。
此事件使应用程序能在系统默许处理程序向用户告知丰裕并终止应用程序以前记录有关十分的音讯。
若是有丰盛的有关应用程序状态的新闻,则足以使用任何办法,如保存程序数据以造福将来举办还原。
指出谨慎行事,因为未经处理的不行时可能会毁掉程序数据。详情请参见MSDN。

     应用的代码如下:

public class MonitorException
{
       [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
       public static void Monitor()
       {
              Application.ThreadException += new ThreadExceptionEventHandler(MainThreadException);
              AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
       }

       public static void UnMonitor()
       {
              Application.ThreadException -= new ThreadExceptionEventHandler(MainThreadException);
              AppDomain.CurrentDomain.UnhandledException -= new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

       }

       private static void MainThreadException(object sender, ThreadExceptionEventArgs e)
       {
              try
              {
                     ShowException(e.Exception);
              }
              catch(Exception ex)
              {
                     GeneralLog.WriteLog(ex);
              }
       }

       private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)

       {
              ShowException((Exception)e.ExceptionObject);
       }

       private static void ShowException(Exception ex)
       {
              GeneralLog.WriteLog(ex);
       }
}

 
  因为那是一个静态事件,所以释放应用程序时务必分离事件处理程序,否则会导致内存泄漏。

10.7     小结

   
至此,框架平台的雏形就已经达成了,二次开发设备驱动、数据显示、数据导出和劳务组件,举办零部件挂载,加载、运行的满贯工艺流程都可以走通了。

    可是,对于二次开发还应有负有调节成效,下一章节中介绍《第11章  
调试器设计》

 

小编:唯笑志在

Email:504547114@qq.com

QQ:504547114

.NET开发技术联盟:54256083

文档下载:http://pan.baidu.com/s/1pJ7lZWf

官方网址:http://www.bmpj.net

相关文章

Your Comments

近期评论

    功能


    网站地图xml地图