目       录

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

10.1        配置文件设计… 3

10.2        加载设备驱动… 4

10.3        加载界面视图… 8

10.4        加载数据导出… 12

10.5        加载服务组件… 14

10.6        全局10分监测… 17

10.7        小结… 19

 

第柒章     宿主程序详细规划

    
前几章对设施驱动、IO实例、外部接口和完好控制器等展开了详实介绍,那个都以框架平台的有机组成部分,那有的相当于后台服务的帮助组件,通过模块化完成框架平台的搭建;宿主程序也是框架平台的一有个别,作为承载插件的多少个软件平台,是人机交互的绝无仅有接口,通过鼠标点击完结各个指令,是插件式框架平台最后要促成的一些。在《第②章
框架总体的筹划》的“2.1
宿主程序设计”中对宿主程序的完好效果和界面进行了统一筹划和陈设,不过并没有关系到细节层面,要落实那一个规划的功能,包蕴3地点工作:界面包车型客车完结,也正是UI布局,涉及到少量的代码控制;与插件(设备驱动、图形展现、数据导出和服务组件)举办互动,把必要的插件加载到宿主程序中,最后传递给后台服务;与《第柒章
总体控制器的统一筹划》中的IDeviceController总控制器接口实行互动,能够清楚为与后台服务的支撑组件进行互相,接收宿主程序的输入,一般为插件新闻、操作响应等。交互的构造示意图如下:

图片 1 

   
宿主程序接受来自人士的动作,通过配备文件完毕加载插件或然把早已加载的插件与总控器进行互动。当然,宿主程序也大概与此外救助理工科程师作举行交互。

10.1     配置文件设计

      
加载插件的点子有不少种,能够透过遍历钦点目录下的程序集,找到相应的插件接口类型,并且加载到框架平台,未来有为数不少编纂软件都以接纳的如此格局。然而笔者深感那种艺术有点有个别暴力,不能够任什么人来到你家门前就同意他进门的。所以,SuperIO框架平台应用一种更温馨的不二法门,通过布置文件加载插件。把叁回开发好的插件音讯配置到相应的文本中,只有插件音讯“合法”的场馆下才会基于气象加载插件到框架平马赛。

依照那样考虑,就须要对配备文件进行规划,以如何的文件格式保存音信,以及都封存什么样的信息。

      配置文件的格式选拔XML格局,对.NET
Framework的System.Configuration.Configuration工具类进行一遍封装。先定义1个接口,对操作配置文件举办规范,接口定义如下图:

图片 2 

    
配置文件保留什么样的新闻,取决于应用进程中所需求的音讯,差别的插件或然用到的配置音信不雷同。那么先定义三个基础的配备消息,包涵:插件文件路径、实例类音讯(命令空间和类名)、标题和标注等新闻,以便能够经过反射工具类加载插件。配置新闻类定义如下图:

图片 3 

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

图片 4

10.2     加载设备驱动

    
设备驱动的布署文件与功底配置文件差别,首要涉及到两部分:可挂载的装置驱动新闻和曾经挂载到框架平台的驱动新闻。

    
可挂载的装置驱动新闻在AssemblyDeviceSectionGroup配置组中开始展览布局,当挂载新的装备驱动的时候,如扩展设备,就会从那么些配置组中加载消息,以便操作人士开始展览抉择。配置组下的设备驱动配置新闻定义如下图:

图片 5 

    当调用扩充设备窗体的时候会从安插文件读取程序集消息,如下图:

图片 6 

    当触发扩展设备事件的时候,会创制新的设施驱动,代码实现如下:

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配置组中展开布署,也便是对已经挂载的装置驱动,在下次起动框架平台的时候要自行把这一个装备驱动挂载到阳台下运转,当产生删除设备驱动事件时从该配置组中删去相关音信。能够安装通信类型变更设备驱动的广播发表格局。配置组下的配制音信定义如下图:

图片 7 

  
当下次起步框架平台时会从那一个配置组加载并实例化设备驱动,挂载到框架平台下运营设备驱动实例,在宿主程序中展现设备驱动实例实时运维情形。加载设备驱动代码如下:

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;
}

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

图片 8

10.3     加载界面视图

   
组态软件会有二个图片和UI引擎来支撑图形数字化显示,允许三次开发者通过拖拽UI组件实行图形化设计,并设置UI组件的性质与IO变量实行关联来体现数据新闻。

   
考虑到开发开支和人工费用,SuperIO没有像组态软件的章程贯彻图形化展现,可是自定义图形化UI展现部分是必须兑现的,满意差别用户、不相同选择场景的急需。

   
SuperIO是通过事件和接口的主意来落成自定义图形展现。设备驱动对数码进行包装,打包后的数目或然是:字符串(数组)、类对象、字节数组等,通过调用事件(OnDeviceObjectChangedHandler)把包裹后的数额以目的的款型传递给图形展现接口(IGraphicsShow),再反向解析数据音讯体今后区别的UI组件上,援救多种显得风格。

    
那么,那样就扶助一遍开发者继承图形展现接口(IGraphicsShow),独立开发一个零件(DLL),并且挂载到布署文件中,当鼠标单事菜单的图纸呈现项时自动以插件的样式加载DLL,并以FormTab的方式展现图形界面。

   
针对加载界面视图的整个进度涉及到:配制文件、加载视图菜单、单击事件呈现视图等。

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

 图片 9

    
当框架平台运行时,会自行加载配置文件,并彰显在界面视图的菜谱中,加载配置文件的代码如下:

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);
       }
}

  
在那个进度中,有三个标题考虑到,便是累累单击同一个食谱视图项时,无法反复突显同1个界面视图窗体,首要考虑到统一筹划的客观和实施的作用。_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;
       }
}

10.4     加载数据导出

   
一般景色下用不到数量导出插件接口功用,然则在做项目标时候的确会生出各个多少格式举办互动的气象,例如:N个厂家要合并本人的多寡音讯,可是规定的多寡格式又不雷同,又迫于用户的威慑,不得不协作工作。那么就能够用数码导出插件来达成。

    
有人会困惑:那样的效率不能够在装置驱动和显示视图中达成吗?当然可以这么操作。不过,作者不想把开发稳定的设施驱动和出示视图成效模块随意扩展代码,更不乐意为了本来不相干的工作可能影响到自然应该干好的作业,对于有“洁癖”的开发者来讲更不甘于那样干。本来设备驱动在框架平纽伦堡即是可变的因子,可是对于数据导出又是相对稳定的片段,所以把数量导出功用重新解耦出来,单独设计成插件组件的主意。

   
那部分作用设计的相比较简单,也是通过配备文件的方法挂载插件,每一趟运营框架平台都会把计划文件中的数据导出插件加载进来,直到框架平台退出。也正是说挂载相应的插件就有对应的导出数据作用,不加载插件就不会有其它操作。

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

 图片 10

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

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;
}

10.5     加载服务组件

    
设备驱动的功力只负责与硬件配备实行彼此,无法把事务性的劳动加到设备驱动中,不然恐怕会潜移默化多少寻常的并行;界面视图只负责对征集上来的数量开始展览实时展现,不可能把事务性的服务加到界面视图中,不然会影响人机交互的体验感;数据导出只负责对数据开始展览格式化并导出到相应的介质中,不能把事务性的服务加到数据导出中,不然数据导出不拥有功效界面包车型客车竞相能力。

    
服务组件针对出色的事务性服务场馆,请参见《7.外部接口的设计》。服务组件的加载进度与界面视图的加载进程看似。

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

图片 11

   
当框架平台运营时,会活动加载配置文件,并展现在劳务的菜系中,加载配置文件的代码如下:

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();
        }
}

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     小结

   
至此,框架平台的雏形就曾经完成了,贰遍开发设备驱动、数据展现、数据导出和劳务组件,进行零部件挂载,加载、运转的满贯工艺流程都得以走通了。

    然而,对于2次开发还应有具备调节效能,下一章节中介绍《第②1章  
调节和测试器设计》

 

笔者:唯笑志在

Email:504547114@qq.com

QQ:504547114

.NET开发技术联盟:54256083

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

合法国网球公开赛址:http://www.bmpj.net

相关文章

网站地图xml地图