目 錄
第八章 總體控制器的設計... 2
8.1 總控制器的職能... 2
8.2 組裝和釋放部件... 3
8.3 事件響應... 5
8.4 小結... 9
有了IO部分、設備驅動部分、顯示部分、數據導出部分和服務組件部分等,在這些已經存在的接口上構建一個集成各部分的總控制器,協調各部分有序工作、事件響應和控制數據流向。
另外,這個總控制器還負責與宿主程序進行交互,可以這樣理解:總控制器是宿主程序與IO部分、設備驅動部分、顯示部分、數據導出部分和服務組件部分之間交互的載體,並且是唯一的。結構示意圖如下:
總控制器(IDeviceController)的職能包括:增加和刪除設備驅動、增加導出數據實例、增加圖形顯示實例、增加服務組件實例、單擊服務事件、釋放控制器資源等等。接口定義如下圖:
DeviceController是總控制器的實例體類,繼承自IDeviceController接口。通過構造函數來完成對總控制器的初始化,代碼如下:
public DeviceController() { _devList = DeviceManager.GetInstance(); _ioController = IOControllerManager.GetInstance(); _runContainer = RunContainerForm.GetRunContainer(); _runContainer.MouseRightContextMenuHandler += RunContainer_MouseRightContextMenuHandler; _dataShowController = new GraphicsShowController(); _exportController = new ExportDataController(); _appServiceManager = new AppServiceManager(); }
通過ReleaseDeviceController接口來完成對總控制器的資源釋放,代碼如下:
public void ReleaseDeviceController() { _ioController.RemoveAllController(); _runContainer.RemoveAllDevice(); _runContainer.MouseRightContextMenuHandler -= RunContainer_MouseRightContextMenuHandler; _exportController.RemoveAll(); _dataShowController.RemoveAll(); _appServiceManager.RemoveAll(); IEnumerator<IRunDevice> devList = _devList.GetEnumerator(); while (devList.MoveNext()) { devList.Current.ExitDevice(); } _devList.RemoveAllDevice(); }
軟件退出時釋放資源要比軟件啟動時加載資源要復雜的多,這塊涉及到兩方面問題:(1)釋放資源順序,如果資源提前釋放,那麼往往會造成後邊代碼在執行過程中出現無法引用對象資源的現象,造成意想不到的結果,所以一定要對實例的可用性進行判斷。(2)事務性的線程無法正常退出,造成軟件界面已經關閉,但是後台進程卻一直存在。特別是對線程退出的處理,框架平台采用了統一的線程退出機制,代碼如下:
public void StartThead() { if (_RunThread == null || !_RunThread.IsAlive) { this._IsExit = false; this._RunThread = new Thread(new ThreadStart(RunThead)); this._RunThread.IsBackground = true; //該線程為後台線程 this._RunThread.Name = "RunThread"; this._RunThread.Start(); } } private void RunThead() { while (!_IsExit) { if(_IsExit) //如果標識為true,則退出循環,退出線程 { break; } //事務處理 } } public void StopThead() { if (this._RunThread != null && this._RunThread.IsAlive) { this._IsExit = true; //標識當前線程為可退出線程。 this._RunThread.Join(1000);//阻塞調用線程,直到某個線程終止或經過了指定時間為止 try { _RunThread.Abort(); //為了防止線程沒有退出,進行強行終止,有可能造成文件損壞 } catch { } } }
增加和刪除設備驅動都會對設備的事件進行綁定和解綁。代碼如下:
dev.DeviceRuningLogHandler += new DeviceRuningLogHandler(DeviceRuningLogHandler); dev.UpdateContainerHandler += new UpdateContainerHandler(UpdateContainerHandler); dev.DeviceObjectChangedHandler += new DeviceObjectChangedHandler(DeviceObjectChangedHandler); dev.ReceiveDataHandler += new ReceiveDataHandler(ReceiveDataHandler); dev.SendDataHandler += new SendDataHandler(SendDataHandler); dev.COMParameterExchangeHandler += new COMParameterExchangeHandler(COMParameterExchangeHandler); dev.DeleteDeviceHandler += new DeleteDeviceHandler(DeleteDeviceHandler);
具體含義請參見《第3章 設備驅動的設計》中的“3.12 事件響應設計”,COMParameterExchangeHandler改變串口參數事件響應代碼如下:
private void COMParameterExchangeHandler(object source, COMParameterExchangeArgs e) { if (e == null) { return; } IRunDevice dev = this._devList.GetDevice(e.DeviceID.ToString()); if (dev != null) { if (dev.CommunicationType == CommunicationType.COM) { if (e.OldCOM != e.NewCOM) { //--------------對舊串口進行處理----------------// IRunDevice[] oldCOMDevList = this._devList.GetDevices(e.OldCOM.ToString(), CommunicationType.COM); //---------------檢測當前串口設備數------------// int existCOMCount = 0; for (int i = 0; i < oldCOMDevList.Length; i++) { if (oldCOMDevList[i].GetHashCode() != dev.GetHashCode()) { existCOMCount++; } } //------------------------------------------// if (existCOMCount <= 0)//該串口沒有可用的設備 { IIOController oldCOMController = IOControllerManager.GetInstance().GetController(SessionCom.FormatKey(e.OldCOM)); if (oldCOMController != null) { _ioController.CloseController(oldCOMController.Key); } else { DeviceMonitorLog.WriteLog(e.DeviceName, "該設備的串口控制器為空"); } } //--------------對新串口進行處理----------------// bool newCOMControllerExist = IOControllerManager.GetInstance().ContainController(SessionCom.FormatKey(e.NewCOM)); if (!newCOMControllerExist) { IIOController newCOMController = _ioController.BuildController(e.NewCOM.ToString(), e.NewBaud.ToString(), CommunicationType.COM); if (newCOMController != null) { newCOMController.StartService(); _ioController.AddController(newCOMController.Key.ToString(), newCOMController); } else { DeviceMonitorLog.WriteLog(e.DeviceName, "創建該設備的串口控制器失敗"); } } DeviceMonitorLog.WriteLog(e.DeviceName, String.Format("串口從{0}改為{1}", e.OldCOM.ToString(), e.NewCOM.ToString())); } else { if (e.OldBaud != e.NewBaud) { ISessionCom comIO = (ISessionCom)SessionComManager.GetInstance().GetIO(SessionCom.FormatKey(e.OldCOM)); if (comIO != null) { bool success = comIO.IOSettings(e.NewBaud); if (success) { DeviceMonitorLog.WriteLog(e.DeviceName, String.Format("串口{0}的波特率從{1}改為{2}成功", e.OldCOM.ToString(), e.OldBaud.ToString(), e.NewBaud.ToString())); } else { DeviceMonitorLog.WriteLog(e.DeviceName, String.Format("串口 {0} 的波特率從 {1} 改為 {2} 失敗", e.OldCOM.ToString(), e.OldBaud.ToString(), e.NewBaud.ToString())); } } } } } else { DeviceMonitorLog.WriteLog(e.DeviceName, "不是串口類型的設備"); } } }
同時,還包括GraphicsShowClosedHandler和MouseRightContextMenuHandler兩個事件。當關閉顯示視圖的時候會觸發GraphicsShowClosedHandler事件,把當前視圖從管理器中移除,並釋放資源;當右鍵單擊顯示視圖會觸發MouseRightContextMenuHandler事件,以調用相應設備的上下文菜單。
總體控制器不是必須的,宿主程序完全可以直接與IO部分、設備驅動部分、顯示部分、數據導出部分和服務組件部分進行交互。但是,為了結構清晰、方便擴展,在中間加了一層進行總體協調。
作者:唯笑志在
Email:[email protected]
QQ:504547114
.NET開發技術聯盟:54256083
文檔下載:http://pan.baidu.com/s/1pJ7lZWf
官方網址:http://www.bmpj.net