重構關注點
- 遵循開閉原則
- 面向抽象設計
- 實現設備程序端可動態配置
重構的需求
領導想省事提出需求,將現有PDA程序修改為支持PC端由電器工程師根據實際的生產流程可配置,PDA程序在讀取配置文件后動態生成導航界面。然后導航綁定的是PDA程序Dll里的界面。公司的綜合賦碼管理系統(CMS)作為服務器端對PDA暴露WCF服務,PDA在執行掃描操作后對CMS發起請求,CMS收到請求后匹配分析PDA的請求,分析完再返回執行結果給PDA。場景就是這樣一個場景,PDA掃描條碼的操作分:掃描一個碼,掃描兩個碼,掃描多個碼三種。領導讓寫3個界面,其實這正好可以抽象一下,相當於1個界面就能搞定;於是設計了一個掃描操作的基類窗體,把掃描的基本操作寫在基類里,使用模板設計模式,掃多少個碼的界面繼承基類重用大部分掃描的處理邏輯。主要流程是PC端通過反射獲取PDA程序的Dll里的窗體類列表,外部定義好PDA要展示的功能清單序列化成為Json格式的文件,PC端使用MTP傳輸到PDA上,PDA讀取該文件來動態生成導航界面。
重構的過程
1)定義數據傳輸對象

using System; using System.Linq; using System.Collections.Generic; using System.Text; namespace ehsure.Core.Data.dto { [Serializable] /// <summary> /// 主界面菜單實體類 /// </summary> public class DesignConfig { /// <summary> /// 界面寬度 /// </summary> public int Width { get; set; } /// <summary> /// 界面高度 /// </summary> public int Height { get; set; } /// <summary> /// 界面下所有控件 /// </summary> public List<ControlsConfig> ControlsList { get; set; } } }

using System; using System.Linq; using System.Collections.Generic; using System.Text; namespace ehsure.Core.Data.dto { [Serializable] /// <summary> /// 控件UI配置參數實體 /// </summary> public class ControlsConfig { /// <summary> /// 控件ID /// </summary> public string ID { get; set; } /// <summary> /// 控件顯示 /// </summary> public string ShowText { get; set; } /// <summary> /// 控件寬度 /// </summary> public int ControlWidth { get; set; } /// <summary> /// 控件高度 /// </summary> public int ControlHeight { get; set; } /// <summary> /// 控件命令字 /// </summary> public string Command { get; set; } /// <summary> /// 控件要打開的界面 /// </summary> public string ForwardForm { get; set; } /// <summary> /// 位置坐標X /// </summary> public int X { get; set; } /// <summary> /// 位置坐標Y /// </summary> public int Y { get; set; } /// <summary> /// 排序號 /// </summary> public int Sort { get; set; } } }
2)重構解決方案
原來的主程序集是個exe,建立職責是UI層的程序集,建立PDA主入口程序集。
3)編碼實現動態導航(使用的自定義控件來代替Button)
自定義控件MenuButton

/// <summary> /// 菜單按鈕,自定義控件 /// </summary> public class MenuButton : Button { public string ActiveFlag = "※"; public string Command { get; set; } public string ForwardForm { get; set; } protected bool itemActiveFlag = false; /// <summary> /// 是否處於被選中狀態 /// </summary> public bool ItemActiveFlag { get { return itemActiveFlag; } set { itemActiveFlag = value; if (value) Text = ActiveFlag + Text; else Text = Text.Replace(ActiveFlag, ""); } } private StringFormat sf; public MenuButton() { BackColor = Color.White; ForeColor = Color.Black; Height = 28; Font = new Font("微軟雅黑", 14F, FontStyle.Bold); sf = new StringFormat(); sf.Alignment = StringAlignment.Center; sf.LineAlignment = StringAlignment.Center; } protected override void OnGotFocus(EventArgs e) { BackColor = SystemColors.Highlight; ForeColor = Color.OrangeRed; ItemActiveFlag = true; } protected override void OnLostFocus(EventArgs e) { BackColor = Color.White; ForeColor = Color.Black; ItemActiveFlag = false; } }
導航工作區的父容器就是一個Panel,MenuButton的高度是動態計算的,寬帶是匹配父容器。
public partial class ShellMainForm : Form { public ShellMainForm() { InitializeComponent(); this.Load += new EventHandler(ShellMainForm_Load); this.KeyPreview = true; this.KeyDown += new KeyEventHandler(ShellMainForm_KeyDown); } void ShellMainForm_KeyDown(object sender, KeyEventArgs e) { if (e.KeyData == Keys.F1) { using (SystemTimeSetForm frm = new SystemTimeSetForm()) { var result = frm.ShowDialog(); if (result.Equals(DialogResult.OK)) { this.statusBar.Text = DateTime.Now.ToLongDateString() + " " + DateTime.Now.DayOfWeek; } } } if (e.KeyData == Keys.F2) { using (var powerManager = new PowerManagement()) { powerManager.SetSystemPowerState(PowerManagement.SystemPowerStates.Suspend); } } } void ShellMainForm_Load(object sender, EventArgs e) { try { Cursor.Current = Cursors.WaitCursor; MaximizeBox = false; MinimizeBox = false; FormBorderStyle = FormBorderStyle.FixedSingle; this.Text = "CMS智能終端"; this.Width = Screen.PrimaryScreen.WorkingArea.Width; this.Height = Screen.PrimaryScreen.WorkingArea.Height; this.Left = 0; this.Top = 0; statusBar.Text = string.Join(" ", new string[] { "線號:" + DeviceContext.GetInstance().GetGlobalConfig().LineNum , "設備號:" + DeviceContext.GetInstance().GetGlobalConfig().DeviceNum }); TestLogin(); DriveInit(); } finally { Cursor.Current = Cursors.Default; } } /// <summary> /// 初始化系統功能列表 /// </summary> /// <param name="config"></param> void InitSystemNavigateBar(DesignConfig config) { var list = config.ControlsList.OrderByDescending(m => m.Sort); if (list.Any()) { int index = 0; //list.Reverse(); foreach (var navigateItem in list) { var btn = new MenuButton(); btn.TabIndex = index; btn.Dock = DockStyle.Top; btn.TabIndex = workareaPanel.Controls.Count; btn.Text = navigateItem.ShowText; btn.ForwardForm = navigateItem.ForwardForm; btn.Click += new EventHandler(NavigateButton_Click); btn.KeyDown += new KeyEventHandler(NavigateButton_KeyDown); workareaPanel.Controls.Add(btn); index++; } } } /// <summary> /// 響應導航按鈕回車事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void NavigateButton_KeyDown(object sender, KeyEventArgs e) { if (e.KeyValue == 13) NavigateButton_Click(sender, null); } /// <summary> /// 響應導航單擊事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void NavigateButton_Click(object sender, EventArgs e) { RunModuleForm((MenuButton)sender); } private void menuClose_Click(object sender, EventArgs e) { if (MessageBox.Show("確認要退出系統", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes) { this.Close(); Application.Exit(); } } /// <summary> /// 動態打開模塊窗體 /// </summary> /// <param name="mb">MenuButton 被點擊的控件 /// mb.ForwardForm要打開的窗體類名:{命名空間+","+類名} /// mb.Command {REPLACE,DELETE...CMS腳本對應的指令名稱}</param> protected void RunModuleForm(MenuButton mb) { try { if (string.IsNullOrEmpty(mb.ForwardForm)) { throw new Exception("模塊或者窗體沒有設定類庫信息!"); } string[] tempModulesInfo = mb.ForwardForm.Split(",".ToCharArray()); Assembly asb = Assembly.Load(tempModulesInfo.FirstOrDefault()); string frmTypeName = string.Join(".", tempModulesInfo); var form = asb.GetTypes().Where(p => p.FullName.Equals(frmTypeName)).FirstOrDefault(); if (form != null) { DeviceContext.GetInstance().OperateTypeText = mb.Text.Replace(mb.ActiveFlag, ""); var frm = (System.Windows.Forms.Form)Activator.CreateInstance(form); if (!string.IsNullOrEmpty(mb.Command)) { DeviceContext.GetInstance().CurrentCommand = mb.Command; } frm.ShowDialog(); } else throw new Exception(string.Format("類名:{0}不存在!", frmTypeName)); } catch (Exception ex) { //throw ex; MessageBox.Show("錯誤描述:" + Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace, "錯誤提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); } } /// <summary> /// 獲取應用程序界面導航配置 /// </summary> /// <returns></returns> protected DesignConfig GetDesignNavigateConfig() { var list = new List<ControlsConfig>(); System.Action<DesignConfig> addDefaultItemTask = (dc) => { dc.ControlsList.Add(new ControlsConfig { ID = Guid.NewGuid().ToString().Replace("-", ""), Command = "", ForwardForm = "ehsure.Smart.FlowUI,AdminSettingForm", ShowText = "設備配置", ControlHeight = 0, ControlWidth = 0, X = 0, Y = 0, Sort = Int32.MaxValue }); }; var path = new DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)); string fileName = path.FullName + @"\Config\DesignConfig.Config"; if (!File.Exists(fileName)) { DesignConfig dc = new DesignConfig { Height = Screen.PrimaryScreen.WorkingArea.Height, Width = Screen.PrimaryScreen.WorkingArea.Width, ControlsList = list }; addDefaultItemTask.Invoke(dc); string fileContext = JsonConvert.SerializeObject(dc); using (var fs = new FileStream(fileName, FileMode.Create)) { byte[] buffer = Encoding.UTF8.GetBytes(fileContext); fs.Write(buffer, 0, buffer.Length); fs.Flush(); fs.Close(); } return dc; } else { using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[fs.Length]; fs.Read(buffer, 0, buffer.Length); string fileContext = Encoding.UTF8.GetString(buffer, 0, buffer.Length); DesignConfig dc = JsonConvert.DeserializeObject<DesignConfig>(fileContext); if (dc != null && !dc.ControlsList.Any(m => m.Sort == Int32.MaxValue)) { addDefaultItemTask.Invoke(dc); } fs.Close(); return dc; } } } /// <summary> /// 測試連接CMS /// </summary> private void TestLogin() { string outMsg; var codeInfo = new TaskDTOCode { Code = "LoginTest" }; CFDataService.SubmitToControl(codeInfo, out outMsg); } /// <summary> /// 加載驅動 /// </summary> private void DriveInit() { string dllName = ScanCache.DllType.DllName; string dllService = ScanCache.DllType.DllService; string[] file = Directory.GetFiles(Path.GetDirectoryName(Assembly.GetCallingAssembly().GetName().CodeBase) + "\\", dllName); if (file.Length == 0) { throw new Exception(ErrorMessage.ScanComponentLoadFailed); } else { Assembly assembly = Assembly.LoadFrom(file[0]); Type typeScanService = assembly.GetType(dllService); ScanCache.BaseScanDirve = (BaseScanDriveService)assembly.CreateInstance(typeScanService.FullName); ScanCache.BaseScanDirve.Init(); } } /// <summary> /// 界面排列布局時觸發,初始化界面導航 /// </summary> /// <param name="e"></param> protected override void OnResize(EventArgs e) { base.OnResize(e); workareaPanel.Controls.Clear(); var config = GetDesignNavigateConfig(); if (config != null) { InitSystemNavigateBar(config); } if (workareaPanel.Controls.Count > 0 && workareaPanel.Height < Screen.PrimaryScreen.WorkingArea.Height) { foreach (Control ctrl in workareaPanel.Controls) { ctrl.Height = workareaPanel.Height / workareaPanel.Controls.Count - 2; } workareaPanel.Controls[workareaPanel.Controls.Count - 1].Focus(); } } }
4)UI層業務窗體的實現是本篇隨筆的重點
重點考量的地方就是前面所說的要面向抽象設計,封裝和繼承。
所有業務窗體的基類

/// <summary> /// 窗體基類 /// </summary> public partial class BaseForm : Form { private bool isScaleDown = true; /// <summary> /// 是否屏幕自適應 /// </summary> public bool IsScaleDown { get { return isScaleDown; } set { isScaleDown = value; } } private bool enterToTab = false; /// <summary> /// 是否回車變Tab /// </summary> public bool EnterToTab { get { return enterToTab; } set { enterToTab = value; } } public BaseForm() { InitializeComponent(); KeyPreview = true; SetInterval(); } private ScannerErrorService ScannerErrorService; private ScannerErrorService getScannerErrorService() { return ScannerErrorService ?? (ScannerErrorService = new ScannerErrorService()); } protected virtual void InitMenu() { } protected override void OnActivated(EventArgs e) { CustomizeCursor.CloseCursor(); base.OnActivated(e); } protected void AddMenuItem(MainMenu mainMenu, string text, ehsure.Common.Action func) { MenuItem item = new MenuItem(); item.Text = text; item.Click += delegate(object sender, EventArgs e) { try { CustomizeCursor.ShowWaitCursor(); func(); } catch (Exception ex) { ShowMessageBoxForm(ex); } finally { CustomizeCursor.CloseCursor(); } }; mainMenu.MenuItems.Add(item); } protected void AddMenuItem(MainMenu mainMenu, string mainText, string text, ehsure.Common.Action func) { MenuItem mi = null; Menu.MenuItemCollection collection = mainMenu.MenuItems; for (int i = 0; i < collection.Count; i++) { MenuItem item = collection[i]; if (string.Equals(item.Text, mainText, StringComparison.OrdinalIgnoreCase)) { mi = item; continue; } } if (mi == null) { mi = new MenuItem(); mi.Text = mainText; mainMenu.MenuItems.Add(mi); } MenuItem sub = new MenuItem(); sub.Text = text; sub.Click += delegate(object sender, EventArgs e) { try { CustomizeCursor.ShowWaitCursor(); func(); } catch (Exception ex) { ShowMessageBoxForm(ex); } finally { CustomizeCursor.CloseCursor(); } }; mi.MenuItems.Add(sub); } protected virtual void FireAction(ehsure.Common.Action action) { try { CustomizeCursor.ShowWaitCursor(); action(); } catch (Exception ex) { ShowMessageBoxForm(ex); } finally { CustomizeCursor.CloseCursor(); } } public virtual void FireActionCode(ActionCode action, string code, int inputType) { try { CustomizeCursor.ShowWaitCursor(); action(code, inputType); } catch (Exception ex) { ShowMessageBoxForm(ex); } finally { CustomizeCursor.CloseCursor(); } } private void BaseForm_Load(object sender, EventArgs e) { InitMenu(); } public void ShowMessageBoxForm(Exception ex) { CustomizeCursor.CloseCursor(); try { string msg = null; msg = ex.Message; string type = ex.GetType().FullName; if (type == "System.Net.WebException") { msg = "網絡異常!"; } if (type != "System.Exception" || msg == ErrorMessage.ScanComponentLoadFailed) { ScannerErrorReport error = new ScannerErrorReport() { Id = Guid.NewGuid().ToString(), ErrorInfo = msg, ErrorTime = DateTime.Now, CustomerCode = ScanCache.UserContext.CorpId, CustomerName = ScanCache.UserContext.CorpName, Remark = ex.StackTrace }; getScannerErrorService().Insert(error); } MessageBoxForm form = new MessageBoxForm(); form.ShowMessage(msg); form.ShowDialog(); } catch (Exception eex) { MessageBoxForm form = new MessageBoxForm(); form.ShowMessage(eex.Message); form.ShowDialog(); } } private void SetInterval() { var file = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase) + "\\App.Config"; XmlDocument doc = new XmlDocument(); if (!File.Exists(file)) { ScanCache.SuccessInterval = 200; ScanCache.ErrorInterval = 3000; return; } doc.Load(file); XmlNodeList nodes = doc.GetElementsByTagName("add"); for (int i = 0; i < nodes.Count; i++) { XmlAttribute att = nodes[i].Attributes["key"]; if (att != null) { if (att.Value == "SuccessInterval") { att = nodes[i].Attributes["value"]; ScanCache.SuccessInterval = Convert.ToInt32(att.Value); } if (att.Value == "ErrorInterval") { att = nodes[i].Attributes["value"]; ScanCache.ErrorInterval = Convert.ToInt32(att.Value); } } } } private void BaseForm_Closed(object sender, EventArgs e) { if (DeviceContext.GetInstance().BarcodeData == null) { DeviceContext.GetInstance().CurrentCommand = string.Empty; DeviceContext.GetInstance().OperateTypeText = string.Empty; } this.Close(); } /// <summary> /// 屏幕自適應 /// </summary> /// <param name="frm"></param> private void ScaleDown() { int scrWidth = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width; int scrHeight = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height; if (scrWidth < this.Width) foreach (System.Windows.Forms.Control cntrl in this.Controls) { cntrl.Width = ((cntrl.Width) * (scrWidth)) / (this.Width); cntrl.Left = ((cntrl.Left) * (scrWidth)) / (this.Width); } if (scrHeight < this.Height) foreach (System.Windows.Forms.Control cntrl in this.Controls) { cntrl.Height = ((cntrl.Height) * (scrHeight)) / (this.Height); cntrl.Top = ((cntrl.Top) * (scrHeight)) / (this.Height); } } /// <summary> /// 遞歸控件 外接事件Enter變Tab /// </summary> /// <param name="ctrl"></param> void SetControlEnterToTab(Control ctrl) { foreach (Control subControl in ctrl.Controls) { if (subControl is TextBox || subControl is DateTimePicker || subControl is ComboBox || subControl is NumericUpDown) { subControl.KeyDown += new KeyEventHandler(ctrl_KeyDown); } if (ctrl.Controls.Count > 0) SetControlEnterToTab(subControl); } } void ctrl_KeyDown(object sender, KeyEventArgs e) { if (e.KeyValue == 13) { var ctrl = sender as Control; if (!string.IsNullOrEmpty(ctrl.Text) && ctrl is TextBox) { var tbx = ctrl as TextBox; tbx.SelectAll(); } WinceApi.keybd_event(9, 0, 0, 0); } } protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); if (e.KeyValue == 27) this.Close(); } protected override void OnLoad(EventArgs e) { if (IsScaleDown) ScaleDown(); if (EnterToTab) SetControlEnterToTab(this); this.Width = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width; this.Height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height; base.OnLoad(e); } }
掃描業務的基類
/// <summary> /// 掃描窗體基類 /// </summary> public partial class ScanBaseForm : BaseForm { /// <summary> /// 操作類型 /// </summary> public string ScanOperateType { get { return lbOperType.Text.Trim(); } set { lbOperType.Text = value; } } /// <summary> /// 需要掃碼個數 /// </summary> public int ScanBarcodeNumber { get { return int.Parse(lbCount.Text.Trim()); } set { lbCount.Text = value.ToString(); } } protected TaskDTOCode _TaskDTOCode = new TaskDTOCode(); protected string _SplitChars = string.Empty; protected string _GroupSplitFlag = string.Empty; /// <summary> /// 需要掃碼的個數 /// </summary> protected int _NeedScanNumber = 0; /// <summary> /// 已經掃描的碼 /// </summary> protected List<string> _BarcodeList = new List<string>(); protected Socket pdaClientSocket = null; public ScanBaseForm() { InitializeComponent(); MaximizeBox = false; MinimizeBox = false; Load += new EventHandler(ScanBaseForm_Load); } #region 掃描處理部分 public delegate void ActingThread(string code, int inputType); /// <summary> /// 窗體激活時啟動掃描頭,綁定事件 /// </summary> /// <param name="e"></param> protected override void OnActivated(EventArgs e) { base.OnActivated(e); ScanCache.BaseScanHandle = new BaseScanHandle(ScanCodeEventHandle); ScanCache.BaseScanDirve.CodeReaded += ScanCache.BaseScanHandle; ScanCache.BaseScanDirve.BeginScan(); tbMessage.Text = "掃描頭已經打開,請掃描!"; } /// <summary> /// 讀取截取字符和多碼分隔符 /// </summary> protected virtual void GetGlobalConfig() { string configPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase) + "\\Config\\Device.Config"; if (File.Exists(configPath)) { using (System.Data.DataSet ds = new System.Data.DataSet()) { ds.ReadXml(configPath); if (ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) { var dt = ds.Tables[0]; _SplitChars = dt.Rows[0]["CodeSplit"] == null ? string.Empty : dt.Rows[0]["SplitChars"].ToString(); _GroupSplitFlag = dt.Rows[0]["CodeSplit"] == null ? string.Empty : dt.Rows[0]["CodeSplit"].ToString(); } } } } /// <summary> /// 截取正確的條碼內容 /// </summary> /// <param name="scanData"></param> /// <returns></returns> protected virtual string ScanCodeToRightCode(string scanData) { if (!string.IsNullOrEmpty(_SplitChars) && string.IsNullOrEmpty(scanData)) { string[] temp = scanData.Split(_SplitChars.ToCharArray()); if (temp.Length > 1) return temp.LastOrDefault(); } return scanData; } /// <summary> /// 掃到碼事件觸發 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ScanCodeEventHandle(object sender, BaseScanEventArgs e) { ActingThread act = new ActingThread(ScanActionExecute); this.BeginInvoke(act, new object[] { e.Message, 1 }); } /// <summary> ///掃描到條碼本地窗體處理 /// </summary> /// <param name="code"></param> /// <param name="inputType"></param> protected virtual void ScanActionExecute(string code, int inputType) { string barcode = ScanCodeToRightCode(code); if (!_BarcodeList.Contains(barcode)) { _BarcodeList.Add(barcode); tbMessage.Text = string.Format("掃描到條碼:{0}", barcode); if (_NeedScanNumber < 10) { int index = _BarcodeList.Count; listView.Items[index - 1].SubItems[0].Text = index.ToString() + "-->"; listView.Items[index - 1].SubItems[1].Text = barcode; listView.Refresh(); } else { int index = _BarcodeList.Count; var li = listView.Items.Add(new ListViewItem(index.ToString())); li.SubItems[0].Text = index.ToString(); li.SubItems.Add(barcode); } } else { new MessageBoxForm().ErrorBeep(); tbMessage.ForeColor = Color.Red; tbMessage.Text = "重復掃描!"; } if (_BarcodeList.Count == _NeedScanNumber) { FireAction(SendRequest); } //選中剛剛掃描到的碼 foreach (ListViewItem item in listView.Items) { if (item.SubItems[1].Text.Trim().Equals(_BarcodeList.LastOrDefault())) { item.Selected = true; } } listView.Focus(); } /// <summary> /// 關閉掃描頭,取消綁定 /// </summary> /// <param name="e"></param> protected override void OnDeactivate(EventArgs e) { base.OnDeactivate(e); ScanCache.BaseScanDirve.CodeReaded -= ScanCache.BaseScanHandle; ScanCache.BaseScanDirve.StopScan(); } #endregion void ScanBaseForm_Load(object sender, EventArgs e) { ScanOperateType = DeviceContext.GetInstance().OperateTypeText; ScanBarcodeNumber = _NeedScanNumber; GetGlobalConfig(); if (_NeedScanNumber < 10) InitNavigateView(); else { lbCount.Text = "N(多個)"; listView.Items.Clear(); } _TaskDTOCode.ParentCode = DeviceContext.GetInstance().CurrentCommand; if (DeviceContext.GetInstance().GetGlobalConfig().IsOpenTcpClient) { pdaClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); pdaClientSocket.Connect(new IPEndPoint(IPAddress.Parse(DeviceContext.GetInstance().GetGlobalConfig().TcpClientIp), DeviceContext.GetInstance().GetGlobalConfig().TcpPort)); if (pdaClientSocket != null && pdaClientSocket.Connected) { tbMessage.Text += (Environment.NewLine + "連接TCP Server成功!"); } } } /// <summary> /// 初始化導航視圖 /// </summary> public virtual void InitNavigateView() { listView.Items.Clear(); for (int i = 0; i < _NeedScanNumber; i++) { var li = listView.Items.Add(new ListViewItem((i + 1).ToString())); li.SubItems[0].Text = "1"; li.SubItems.Add("請掃描..."); } } /// <summary> /// 對CMS發起請求 eg: { Code = txt_BoxCode.Text.Trim(), EptCode = txt_BagCode.Text.Trim(), ParentCode = "EA_BOX_BAG" }; /// </summary> protected virtual void SendRequest() { tbMessage.Text += (Environment.NewLine + "正在發起請求,請等待CMS回應..."); DeviceContext.GetInstance().BarcodeData = _TaskDTOCode; if (!DeviceContext.GetInstance().GetGlobalConfig().IsOpenTcpClient) { #region WCF請求 string msgifno = ""; try { Cursor.Current = Cursors.WaitCursor; CFDataService.SubmitToControl(_TaskDTOCode, out msgifno); } catch (Exception ex) { tbMessage.Text += "CMS返回錯誤消息:" + ex.Message; return; } finally { Cursor.Current = Cursors.Default; } if (!string.IsNullOrEmpty(msgifno)) { tbMessage.Text += (Environment.NewLine + msgifno); } else { tbMessage.Text += "操作失敗,CMS服務器端無響應!"; } #endregion } else { if (pdaClientSocket != null && !pdaClientSocket.Connected) { pdaClientSocket.Connect(new IPEndPoint(IPAddress.Parse(DeviceContext.GetInstance().GetGlobalConfig().TcpClientIp), DeviceContext.GetInstance().GetGlobalConfig().TcpPort)); } if (pdaClientSocket == null || !pdaClientSocket.Connected) { tbMessage.Text += (Environment.NewLine + "和CMS服務器端建立連接失敗!"); } byte[] buffer = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(_TaskDTOCode)); try { Cursor.Current = Cursors.WaitCursor; pdaClientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None); byte[] revBuffer = new byte[1024]; int len = pdaClientSocket.Receive(revBuffer, SocketFlags.None); if (len > 0) { string resultMessage = Encoding.UTF8.GetString(revBuffer, 0, len); tbMessage.Text += (Environment.NewLine + resultMessage); } } catch (Exception ex) { tbMessage.Text += (Environment.NewLine + ex.Message); } finally { Cursor.Current = Cursors.Default; } } } private void menuItem2_Click(object sender, EventArgs e) { Close(); } private void menuItem1_Click(object sender, EventArgs e) { if (_BarcodeList.Count != _NeedScanNumber && _NeedScanNumber < 10) { tbMessage.Text += (Environment.NewLine + "掃描條碼個數不正確!"); return; } FireAction(SendRequest); } private void menuItem3_Click(object sender, EventArgs e) { if (_BarcodeList.Count > 0) { tbMessage.Text = "已清空,請開始掃描!"; _BarcodeList.Clear(); int index = 0; foreach (ListViewItem item in listView.Items) { index++; item.SubItems[0].Text = index.ToString(); item.SubItems[1].Text = "請掃描..."; } listView.Refresh(); } else { new MessageBoxForm().ErrorBeep(); tbMessage.Text = "已掃編碼數量為0,請開始掃描!"; } } }
具體子類是實現,只是需要幾行代碼。
[ModuleDescription("外部可調用","掃1個碼進行操作,適用於整箱刪除,查關聯關系等操作。")] public partial class ScanOneForm : ScanBaseForm { public ScanOneForm() { InitializeComponent(); _NeedScanNumber = 1; Menu = mainMenu2; } protected override void SendRequest() { _TaskDTOCode.Code = _BarcodeList.FirstOrDefault(); _TaskDTOCode.EptCode = ""; base.SendRequest(); } }

[ModuleDescription("外部可調用","掃兩個碼進行操作,適用於比如單品替換,添加到箱等操作。")] public partial class ScanTwoForm : ScanBaseForm { public ScanTwoForm() { InitializeComponent(); _NeedScanNumber = 2; Menu = mainMenu2; } protected override void SendRequest() { _TaskDTOCode.Code = _BarcodeList.FirstOrDefault(); _TaskDTOCode.EptCode = _BarcodeList.LastOrDefault(); base.SendRequest(); } }

[ModuleDescription("外部可調用","掃N個碼進行操作,適用批量處理等操作。碼之間用分隔符連接,N指的是大於10的情況。")] public partial class ScanNForm : ScanBaseForm { public ScanNForm() { InitializeComponent(); _NeedScanNumber = 11; Menu = mainMenu2; } protected override void SendRequest() { _TaskDTOCode.Code = string.Join(_GroupSplitFlag, _BarcodeList.ToArray()); _TaskDTOCode.EptCode = ""; base.SendRequest(); } }
重構的心得
又是一次認真思考過后的編程實踐。總之,不是為了完成任務而編碼。
重構的成果
這樣的文章只是適合自己記錄一下,編碼心得,思路。對外人好像也沒啥用吧。只是覺得好久不寫博客,練習一下。