C#WinCE程序(.NET Compact Framework 3.5)项目重构面向抽象设计

重构关注点

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

重构的需求

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

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 = 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,请开始扫描!";
            }
        }

    }

重构的心得

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

重构的成果

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

时间: 2024-10-14 07:13:06

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

VS2008开发WinCE程序编译速度慢的解决办法

VS2008开发WinCE程序编译速度慢的解决办法 VS2008环境下采用C#..NET Compact Framework开发WinCE.Windows Mobile程序时,编译项目非常慢,有时候需要几分钟甚至十几分钟,如果出现这种情况,除了排除机器配置问题外,你可以修改VS的配置文件,以屏蔽掉编译中不需要的任务,这个修改可以让你的编译速度大大提高,有可能你的编译时间只需要几秒钟就搞定了啊. 1.找到以下文件 C:\Windows\Microsoft.NET\Framework\v3.5\Mi

C#-.Net Framework和.Net Compact Framework

.Net Compact Framework 一种独立于硬件的环境,用于在资源受限制的计算设备上运行程序.它继承了公共语言运行时的完整 .NET Framework 结构,支持 .NET Framework 类库的子集,并且包含专为 .NET Compact Framework 设计的类.所支持的设备包括:个人数据助理 (PDA)(如 Pocket PC),移动电话,机顶盒,汽车计算设备,以及安装有 Microsoft Windows CE .NET 操作系统的自定义设计的嵌入设备. 从严格意义

WP移动设备压缩与解压控件Xceed Zip for .NET Compact Framework控件下载及详细介绍使用方法

Xceed Zip for .NET Compact Framework 控件是一款健全的文件压缩和解压缩控件,提供了灵活的ZIP.gZip.流压缩,分割和合并ZIP,创建自定义解压文件. 具体功能: 完全支持.NET Compact Framework 2.0以及以上 100%可管理的代码,由C#编写,面向对象设计 支持在硬盘.内存.FTP站点里创建新的ZIP文件,或者更新存在的ZIP文件 完全兼容WinZip12,支持LZMA算法 支持Zip64 Zip文件格式,对文件大小没有限制 支持从硬

.NET Compact Framework的软件编程开发工具包

LEADTOOLS Mobile Imaging控件是一款针对微软.NET Compact Framework的软件编程开发工具包:采用它,开发者能在个人数字助理(PDA)及移动电话等设备应用设计中使用LEADTOOLS的图象处理功能. 产品特征: 文件格式支持- 支持常见的各种标准图像格式读.写和转换,包括JPEG.JPEG2000.LEAD CMP,.LEAD CMW.TIFF(可以是未压缩的.采用RLE压缩.采用LZW压缩.采用传真(CCITT/G3/G4)压缩).及GIF.PNG.BMP

MVC应用程序使用Entity Framework

创建空的MVC应用程序,为了想使用Entity Framework的类库,发现即无法正常引用.如下图,Insus.NET已经明确引了System.Data.Entity(下图Highlight的代码),但类别在继承DbContext时,却无法正确常引用. 去微软MSDN查看资料:http://msdn.microsoft.com/en-us/library/system.data.entity(v=vs.103).aspx Insus.NET所创建的MVC应用程序也是.NET Framework

java面向抽象编程,可以让程序员专注于程序的逻辑结构设计

/* *建立的抽象类,把这个抽象类交给别人,别人的类需要继承该抽象类 *求得一个立体的底面积,但是我们可以不用管别人是怎么这个底面积的. */ package com.pan.e1; /** * * 作者:属于雨灵的夜 */ public abstract class Gemetry { public abstract double getArea(); } 因为我们希望代码能实现各种类型的体积,所以我们把需要经常变化的底面积作为抽象类,让它作为它的子类的上转类型. /* *面向抽像类,设计主体

关于项目重构,知道真相的程序员眼泪笑了出来

本文授权转载,作者:非著名程序员(公众号:smart_android) 其实过完年回来,我们的项目也一直在强调重构,在实践重构中,但是到目前为止,基本没啥进度.关于项目的重构,我说:基本上大部分都是骗人的.你们信不信?那你可能会问:为什么一开始不把代码写的更好一些,逻辑更严密一些呢?那欢迎大家看我写的这篇文章<代码质量差,bug多?我们都是被逼的 >,看完你会深有同感的. 关于项目重构的问题,为什么一直做不完呢?直到我在浏览微博时,看到了一个非常好玩的对话,可谓是:感同身受,深有同感.知道真相

小程序开发商可以在哪里接项目订单/有几种接单方式

随着移动互联网的发展,5G时代已经来临,智能手机的普及和移动信号的增强,互联网的市场越来越清晰明了,整个市场也越来越开阔.许多传统企业也开始跟随潮流要对接移动互联网行业,这一需求推动了小程序制作领域的发展,市场上就是这样有需求就有供给,有这么大的需求市场,同样也有庞大从事小程序开发的软件企业在占领这个市场.那么小程序服务商在哪里才能接到项目呢?1.同事和朋友等熟人介绍这种成功率比较高,因为开发团队和外包方建立了间接的熟人关系,因此在合作讨论.报价.沟通上都会更顺利.2.社群接单现在是大众创业.万

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

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