重构关注点

  • 遵循开闭原则
  • 面向抽象设计
  • 实现设备程序端可动态配置

重构的需求

领导想省事提出需求,将现有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; }
}
}

DesignConfig

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

ControlsConfig

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

MenuButton

导航工作区的父容器就是一个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 = ;
this.Top = ;
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 = ;
//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 == )
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 = ,
ControlWidth = ,
X = ,
Y = ,
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, , 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, , buffer.Length);
string fileContext = Encoding.UTF8.GetString(buffer, , 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 == )
{
throw new Exception(ErrorMessage.ScanComponentLoadFailed);
}
else
{
Assembly assembly = Assembly.LoadFrom(file[]);
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 > && workareaPanel.Height < Screen.PrimaryScreen.WorkingArea.Height)
{
foreach (Control ctrl in workareaPanel.Controls)
{
ctrl.Height = workareaPanel.Height / workareaPanel.Controls.Count - ;
}
workareaPanel.Controls[workareaPanel.Controls.Count - ].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 = ; 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 = ;
ScanCache.ErrorInterval = ;
return;
}
doc.Load(file);
XmlNodeList nodes = doc.GetElementsByTagName("add");
for (int i = ; 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 > )
SetControlEnterToTab(subControl);
}
} void ctrl_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyValue == )
{
var ctrl = sender as Control;
if (!string.IsNullOrEmpty(ctrl.Text) && ctrl is TextBox)
{
var tbx = ctrl as TextBox;
tbx.SelectAll();
}
WinceApi.keybd_event(, , , );
}
} protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyValue == )
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 = ;
/// <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 > && ds.Tables[].Rows.Count > )
{
var dt = ds.Tables[];
_SplitChars = dt.Rows[]["CodeSplit"] == null ? string.Empty : dt.Rows[]["SplitChars"].ToString();
_GroupSplitFlag = dt.Rows[]["CodeSplit"] == null ? string.Empty : dt.Rows[]["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 > )
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, });
} /// <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 < )
{
int index = _BarcodeList.Count;
listView.Items[index - ].SubItems[].Text = index.ToString() + "-->";
listView.Items[index - ].SubItems[].Text = barcode;
listView.Refresh();
}
else
{
int index = _BarcodeList.Count;
var li = listView.Items.Add(new ListViewItem(index.ToString()));
li.SubItems[].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[].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 < )
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 = ; i < _NeedScanNumber; i++)
{
var li = listView.Items.Add(new ListViewItem((i + ).ToString()));
li.SubItems[].Text = "";
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, , buffer.Length, SocketFlags.None);
byte[] revBuffer = new byte[];
int len = pdaClientSocket.Receive(revBuffer, SocketFlags.None);
if (len > )
{
string resultMessage = Encoding.UTF8.GetString(revBuffer, , 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 < )
{
tbMessage.Text += (Environment.NewLine + "扫描条码个数不正确!");
return;
}
FireAction(SendRequest);
} private void menuItem3_Click(object sender, EventArgs e)
{
if (_BarcodeList.Count > )
{
tbMessage.Text = "已清空,请开始扫描!";
_BarcodeList.Clear();
int index = ;
foreach (ListViewItem item in listView.Items)
{
index++;
item.SubItems[].Text = index.ToString();
item.SubItems[].Text = "请扫描...";
}
listView.Refresh();
}
else
{
new MessageBoxForm().ErrorBeep();
tbMessage.Text = "已扫编码数量为0,请开始扫描!";
}
} }

具体子类是实现,只是需要几行代码。

  [ModuleDescription("外部可调用","扫1个码进行操作,适用于整箱删除,查关联关系等操作。")]
public partial class ScanOneForm : ScanBaseForm
{
public ScanOneForm()
{
InitializeComponent();
_NeedScanNumber = ;
Menu = mainMenu2;
} protected override void SendRequest()
{
_TaskDTOCode.Code = _BarcodeList.FirstOrDefault();
_TaskDTOCode.EptCode = "";
base.SendRequest();
}
}
[ModuleDescription("外部可调用","扫两个码进行操作,适用于比如单品替换,添加到箱等操作。")]
public partial class ScanTwoForm : ScanBaseForm
{
public ScanTwoForm()
{
InitializeComponent();
_NeedScanNumber = ;
Menu = mainMenu2;
} protected override void SendRequest()
{
_TaskDTOCode.Code = _BarcodeList.FirstOrDefault();
_TaskDTOCode.EptCode = _BarcodeList.LastOrDefault();
base.SendRequest();
}
}

扫描2个码

[ModuleDescription("外部可调用","扫N个码进行操作,适用批量处理等操作。码之间用分隔符连接,N指的是大于10的情况。")]
public partial class ScanNForm : ScanBaseForm
{
public ScanNForm()
{
InitializeComponent();
_NeedScanNumber = ;
Menu = mainMenu2;
} protected override void SendRequest()
{
_TaskDTOCode.Code = string.Join(_GroupSplitFlag, _BarcodeList.ToArray());
_TaskDTOCode.EptCode = "";
base.SendRequest();
}
}

扫描N个码

重构的心得

又是一次认真思考过后的编程实践。总之,不是为了完成任务而编码。

重构的成果

这样的文章只是适合自己记录一下,编码心得,思路。对外人好像也没啥用吧。只是觉得好久不写博客,练习一下。

C#WinCE程序(.NET Compact Framework 3.5)项目重构面向抽象设计的更多相关文章

  1. ".NET Compact Framework v2.0 could not be found."

    参考: http://blog.csdn.net/godcyx/article/details/7348431 问题原因: That's a known issue where VS can't di ...

  2. WinCE程序调试方法【转】

    刚刚接触WinCE编程,感觉大部分跟WinForm一样.刚开始的时候,不知道怎么进行断点调试,后来同事告诉我,可以直接连接进行断点调试,一试之下,果然好用,所以拿出来分享一下. 必备工具: Micro ...

  3. .NET Compact Framework Data Provider for SQL Server CE

    .NET Compact Framework Data Provider for SQL Server Mobile Standard Data Source=MyData.sdf;Persist S ...

  4. MVC中使用EF(1):为ASP.NET MVC程序创建Entity Framework数据模型

    为ASP.NET MVC程序创建Entity Framework数据模型 (1 of 10) By  Tom Dykstra |July 30, 2013 Translated by litdwg   ...

  5. visual studio 2017 installer 安装包制作过程出现的问题---此安装程序需要.NET Framework 版本 3.5,请安装该版本,然后重新运行此安装程序,可以从Web获得.NET Framework 。要立即做此事吗?

    图一 visual studio 2017 installer 打包完成以后进行安装时,提示信息 “安装此安装程序需要.NET Framework 版本 3.5,请安装该版本,然后重新运行此安装程序, ...

  6. wince程序调用另外一个wince exe程序?

    记住:要释放句柄 清空内存(当前程序) 在虚拟机下测试如图: 在reyo.ini文件中配置另一wince执行程序的路径,如果不配置程序会报错: 如果配置的程序不存在报错: 没有问题就调用所在位置的wi ...

  7. 在PC上像普通winform程序调试WINCE程序

    在PC上像普通winform程序调试WINCE程序 步骤: 1. 在VS2008中到 工具→选项→设备工具→设备,选择对应的平台,另存为新的名称,如CEDesktopRun,关闭VS2008.(如果不 ...

  8. 将基于 .NET Framework 的 WPF 项目迁移到基于 .NET Core 3

    在 Connect(); 2018 大会上,微软发布了 .NET Core 3 Preview,以及基于 .NET Core 3 的 WPF:同时还发布了 Visual Studio 2019 预览版 ...

  9. 如何通过.Net Compact Framework来获得应用程序的当前路径

    在Win CE上是没有驱动器的概念的,所以要想使用System.IO.Directory.GetCurrentDirectory()来获得当前路径的话,在CF中会遇到未知错误.   应该使用Path. ...

随机推荐

  1. oralce11g导出dmp然后导入Oracle10g

    一次Oracle11g数据库导入 Oracle10g数据库操作笔记 11g备份导入10g的时候会抛错直接阻止导入. 但是有时候还必须得把11g的数据库导入到10g我今天就遇到了这种情况. 一开始 ...

  2. Windows Azure系列-- 配置Azure Power Shell

    1.下载Azure Power shell https://azure.microsoft.com/en-us/documentation/articles/powershell-install-co ...

  3. 【swift-总结】函数

    swift的函数在swift2中的使用改变了不少 /** *param: personName 參数 *returns: String为返回值 */ func sayHello(personName: ...

  4. C++11新特性应用--介绍几个新增的便利算法(不更改容器中元素顺序的算法)

    总所周知.C++ STL中有个头文件,名为algorithm.即算法的意思. The header<algorithm>defines a collection of functions ...

  5. javaweb:推断当前请求是否为移动设备訪问

    这段时间都是在做pc端的业务.结果经理找到我说,可能要做移动端的应用,后台逻辑还是用我写的逻辑.可是须要修改一些,看看怎么处理. 因为移动端和pc端还是略微有些差别的,我认为最好是在一个地儿统一推断, ...

  6. 虚拟数据库_json_ajax

    html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  7. [转]压缩感知重构算法之分段正交匹配追踪(StOMP)

    分段正交匹配追踪(StagewiseOMP)或者翻译为逐步正交匹配追踪,它是OMP另一种改进算法,每次迭代可以选择多个原子.此算法的输入参数中没有信号稀疏度K,因此相比于ROMP及CoSaMP有独到的 ...

  8. React学习总结(一)

    React学习总结 一.什么是React? 是Facebook公司开发的一套JS库 React的详细介绍https://www.jianshu.com/p/ae482813b791 二.老版本Reac ...

  9. 【CSS3】内联、内部、外部样式,样式优先级、层叠、继承

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. 二叉树Binary_Tree(1):二叉树及其数组实现

    定义 二叉树: 二叉树是一种特殊的树.二叉树的特点是每个结点最多有两个儿子,左边的叫做左儿子,右边的叫做右儿子,或者说每个结点最多有两棵子树.更加严格的递归定义是:二叉树要么为空,要么由根结点.左子树 ...