[Serialization] C # communication (Serial Port and network) Framework Design and Implementation-10. Detailed host program design,

Source: Internet
Author: User

[Serialization] C # communication (Serial Port and network) Framework Design and Implementation-10. Detailed host program design,

Contents

Chapter 10 detailed Host Program Design... 2

10.1 configuration file design... 3

10.2 load the device driver... 4

10.3 load the interface view... 8

10.4 load data export... 12

10.5 load service components... 14

10.6 global exception monitoring... 17

10.7 summary... 19

 

Chapter 10 detailed Host Program Design

The previous chapters detail device drivers, I/O instances, external interfaces, and overall controllers. These are an integral part of the Framework Platform, which is equivalent to the supporting components of background services, build a framework platform through modularization. The host Program is also part of the Framework Platform. As a software platform that carries plug-ins, it is the only interface for human-computer interaction. Various commands are completed by clicking the mouse, is the final part of the plug-in Framework Platform. The overall functions and interfaces of the Host Program are planned and designed in "2nd Host Program Design" in Chapter 2.1 Overall framework design, but the details are not involved, these design functions should be implemented, including three aspects: Implementation of the interface, namely the UI layout, involving a small amount of code control; interacts with plug-ins (device drivers, graphic display, data export, and service components), loads the required plug-ins into the host Program, and finally passes them to the background service; interaction with the IDeviceController Controller Interface in Chapter 8th overall controller design can be understood as interaction with the supporting components of the background service to receive input from the host Program, it is generally the plug-in information, operation response, and so on. The interaction structure is as follows:

 

The host program accepts actions from personnel, loads the plug-in through the configuration file, or interacts the loaded plug-in with the master controller. Of course, the host Program may also interact with other secondary transactions.

10.1 configuration file Design

There are many ways to load plug-ins. You can traverse the assembly in the specified directory, find the corresponding plug-in interface type, and load it to the Framework Platform, currently, many editing software uses this method. However, I feel that this method is somewhat violent, so no one can come to your door to allow him to enter the door. Therefore, the SuperIO Framework Platform uses a more user-friendly method to load plug-ins through configuration files. Configure the plug-in information after secondary development to the corresponding file. The plug-in will be loaded to the Framework Platform only when the plug-in information is "legal.

Based on this idea, you need to design the configuration file, save the information in what format, and save what information.

The Configuration file format uses XML to encapsulate the. NET Framework System. Configuration. Configuration tool class twice. Define an interface to standardize the operation configuration file. The interface definition is as follows:

 

The information stored in the configuration file depends on the information required during the application process. Different plug-ins may use different configuration information. First, define a basic configuration information, including the plug-in file path, instance class information (Command Space and class name), title, and annotation, so that you can load the plug-in through the reflection tool class. The configuration information class is defined as follows:

 

The format of the file generated by using the configuration file operation base class is as follows:

10.2 load device drivers

The device driver configuration file is different from the basic configuration file. It involves two parts: the device driver information that can be mounted and the driver information that has been mounted to the Framework Platform.

The device driver information that can be mounted is configured in the AssemblyDeviceSectionGroup Configuration group. When a new device driver is mounted, information is loaded from the Configuration group if a device is added, this allows the operator to select. The device driver configuration information in the configuration group is defined as follows:

 

When a device form is added, the assembly information is read from the configuration file, for example:

 

When a device event is triggered, a new device driver is created. The Code is as follows:

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. devicePara Meter. 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. isReg License = true; dev. CommunicationType = type; dev. UserLevel = UserLevel. High; dev. InitDevice (devid); if (! Device. debugDevice. isDebug) {// -------------------- prepare the device information in the file ---------------------- // 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 ;}

The driver information that has been mounted to the Framework Platform is configured in the CurrentDeviceSectionGroup Configuration group, that is, the mounted device driver, when you start the Framework Platform next time, you need to automatically mount these device drivers to the platform for running. When a device driver deletion event occurs, you can delete the relevant information from the Configuration group. You can set the communication type to change the communication mode of the device driver. Configuration group configuration information is defined as follows:

 

When the Framework Platform is started next time, the device driver will be loaded from this configuration group and instantiated, mounted to the running device driver instance under the Framework platform, and the real-time running status of the device driver instance will be displayed in the Host Program. The code for loading the device driver is as follows:

Public static List <IRunDevice> LoadDevicesFromXml () {List <IRunDevice> list = new List <IRunDevice> (); CurrentDeviceSectionGroup curgroup = (CurrentDeviceSectionGroup) _ Source. configuration. getSectionGroup ("CurrentDeviceSectionGroup"); if (curgroup = null) {throw new feature ("Get the current device configuration information blank");} AssemblyDeviceSectionGroup asmgroup = (AssemblyDeviceSectionGroup) _ Source. configuration. getSectionGroup ("AssemblyDeviceSectionGroup"); if (asmgroup = null) {throw new NullReferenceException ("Get device assembly information blank");} 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 ;}

The overall configuration file of the device driver is as follows:

10.3 load the interface View

The configuration software has a graphical and UI engine to support digital display of graphics, allowing secondary developers to drag and drop the UI components for graphical design, set the attributes of the UI component to be associated with the IO variable to display the data information.

Considering the development cost and labor cost, SuperIO does not implement graphical display like the configuration software, but the custom graphical UI display must be implemented to meet the needs of different users and different application scenarios.

SuperIO displays custom images through events and interfaces. The device driver packages the data. The packaged data may be a string (array), a class object, or a byte array. by calling the event (OnDeviceObjectChangedHandler) the packaged data is passed to the graphic display interface (IGraphicsShow) in the form of an object, and the reverse parsing data information is displayed on different UI components. Multiple display styles are supported.

In this way, secondary developers can inherit the graphic display interface (IGraphicsShow), develop a component (DLL) independently, and mount it to the configuration file, the DLL is automatically loaded as a plug-in when the graphical display item of the mouse single-event menu is displayed as a FormTab.

The entire process of loading the interface view involves: preparing the file, loading the View menu, and clicking the event display view.

The configuration file is the same as the basic configuration file. The configuration file definition is as follows:

 

When the Framework Platform is started, the configuration file is automatically loaded and displayed in the menu in the interface view. The code for loading the configuration file is as follows:

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

When you click a menu item, the ViewItem_ItemClick function is triggered and the View Interface is loaded and displayed. The Code defined is as follows:

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

In this process, one problem is that when you click the same menu view item multiple times, the same interface view form cannot be displayed multiple times, it mainly takes into account the rationality of the design and the efficiency of implementation. The code for the _ DeviceController. AddGraphicsShow (IGraphicsShow) form) function is defined as follows:

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}> display view opened", graphicsShow. thisName); return true;} else {DeviceMonitorLog. writeLog (String. format ("<{0}> display view already exists", graphicsShow. thisName); return false ;}}
10.4 load data and export

Generally, the data export plug-in interface function is not used, but multiple data formats are used for interaction during project creation. For example, N manufacturers need to integrate their own data information, however, the specified data format is different, and users are forced to cooperate. You can use the data export plug-in.

Some people may question: can this function be completed in the device driver and display view? Of course you can do this. However, I do not want to add code to the development of stable device drivers and display view function modules at will, and I do not want to influence what should have been done well for irrelevant things, developers with "Jie Li" are reluctant to do so. The device driver is a variable factor in the framework platform, but it is relatively stable for data export. Therefore, the data export function is decoupled and independently designed as a plug-in component.

This part of the function design is relatively simple, and the plug-in is mounted through the configuration file. Every time the framework Platform is started, the data export plug-in the configuration file will be loaded until the Framework Platform exits. That is to say, the corresponding plug-in has the corresponding data export function, and no operation will be performed without loading the plug-in.

The configuration file is the same as the basic configuration file. The configuration file definition is as follows:

 

The code for loading a plug-in is defined as follows:

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 ("Get Export assembly information blank");} 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 load service components

The device-driven function is only responsible for interacting with hardware devices. Do not add transactional services to the device driver; otherwise, normal data interaction may be affected; the interface view is only responsible for displaying collected data in real time. It cannot add transactional services to the interface view. Otherwise, it will affect the experience of human-computer interaction; data export is only responsible for formatting and exporting data to the corresponding media. It cannot add transactional services to data export. Otherwise, data export does not have the interactive capability on the functional interface.

For special transactional service scenarios, see 7. external interface design. The loading process of service components is similar to that of the interface view.

The configuration file is the same as the basic configuration file. The configuration file definition is as follows:

When the Framework Platform is started, the configuration file is automatically loaded and displayed in the service menu. The code for loading the configuration file is as follows:

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

The _ DeviceController. AddAppService (serviceList) Code adds the service plug-in instance to the controller. The Code is as follows:

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}> Application service opened", service. thisName);} else {DeviceMonitorLog. writeLog (String. format ("<{0}> application service already exists", service. thisName ));}}}

When you click a service item in the menu, the ServiceItem_ItemClick function is called and the Click Event function of the service component is called. The Code is as follows:

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

The stability of the Framework Platform has always been a top priority. Other unknown exceptions may occur during the running process. For these exceptions, try... Catch... To capture.

When the Framework Platform is started, the ThreadException and UnhandledException events are added to capture unknown exceptions, and the exception information in the events is recorded in detail.

ThreadException event, which allows Windows Forms applications to handle other unprocessed exceptions in Windows Forms threads. Attach the event handler to the ThreadException event to handle these exceptions because these exceptions leave your application unknown. Use structured exception handling blocks as much as possible to handle exceptions. For more information, see MSDN.

UnhandledException event, which provides notifications of exceptions not captured. This event enables the application to record information about the exception before the system default handler reports the exception to the user and terminates the application. If you have enough information about the application status, you can take other measures, such as saving program data for future recovery. Exercise caution because the program data may be damaged in the case of unhandled exceptions. For more information, see MSDN.

The application code is as follows:

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

Because this is a static event, you must detach the event handler when releasing the application; otherwise, memory leakage may occur.

Conclusion 10.7

Now, the prototype of the Framework Platform has been completed. The device driver, data display, data export, and service components of the secondary development are mounted, the entire process of loading and running can be passed.

However, for secondary development, debugging functions should also be available. Chapter 1 debugger design will be introduced in the next chapter.

 

Author: Wei Xiaozhi

Email: 504547114@qq.com

QQ: 504547114

. NET Development Technology Alliance: 54256083

Document Download: http://pan.baidu.com/s/1pJ7lZWf

Http://www.bmpj.net

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.