[原创] 上位机软件类编写心得

wateras1   2012-7-28 12:34 楼主
开发上位机软件的语言有很多,为何偏偏选中了.NET呢,主要是因为这个语言开发上位机软件相当方面而且微软提供了大量的类库和API。虽然底层实现代码不像JAVA一样可以开源的,但是这个不影响这门语言的推广,试问有几个人会真正意义上去研究底层的代码呢?再说我们是搞工程的,在保证质量的前提下追求的是速度。而且。NET开发图形界面是相当方便的,不像JAVA一样代码都要自己一笔一笔的写蛮麻烦。对于,NET开发上位机软件,我们应该做到什么程度才算用的比较熟练了呢?我觉得应该是自己会创建类,其实,NET最重要的就是类。每个公司都有自己专门的类库,这就是为何有些公司动不动一个月就出一个新产品了。就是因为人家自己公司的类库相当强大。好多东西已经集成好了就需要调用相应的APIOK了。这次我就专门分享下自己这次做的类。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace lesson
{
    class userserver
    {   
        ///
        /// 检验登录是否成功
        ///
        ///
        ///
        ///
        public bool CheckeLogin(userinfor user,ref string message)
        {
            XmlDocument doc = new XmlDocument();
           doc.Load(AppDomain.CurrentDomain.BaseDirectory + "file\\UserInfor.xml");
            XmlNode root = doc.DocumentElement;
            XmlNode target = root.SelectSingleNode(string.Format("//user[@id='{0}']",user.Username));
            if (target != null)
            {
                XmlElement xe = (XmlElement)target;
                if (xe.GetAttribute("password") == user.Password)
                {
                    message = "登陆成功";
                    return true;
                }
                else
                {
                    message = "密码错误";
                    return false;
                }
            }
            else
            {
                message = "用户名不存在";
                return false;
            }
        
        }
        ///
        /// 修改密码
        ///
        ///
        ///
        ///
        public bool changepwd(userinfor  user, ref string message)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(AppDomain.CurrentDomain.BaseDirectory + "file\\UserInfor.xml");
            XmlNode root = doc.DocumentElement;
            XmlNode target = root.SelectSingleNode(string.Format("//user[@id='{0}'and @password='{1}']", user.Username,user.Password));
            if (target != null)
            {
                XmlElement xe = (XmlElement)target;
                xe.SetAttribute("password", user.Newpassword);
                doc.Save(AppDomain.CurrentDomain.BaseDirectory + "file\\UserInfor.xml");
                message = "修改成功";
                return true;
            }
            else
            {
                message = "原密码错误";
                return false;
            }
        }
        ///
        /// 添加用户信息
        ///
        ///
        ///
        ///
        public bool adduser(userinfor user, ref string message)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(AppDomain.CurrentDomain.BaseDirectory + "file\\UserInfor.xml");
            XmlNode root = doc.DocumentElement;
            XmlNode target = root.SelectSingleNode(string.Format("//user[@id='{0}']", user.Username));
            if (target == null)
            {
                XmlElement xe = doc.CreateElement("user");
                xe.SetAttribute("id",user.Username);
                xe.SetAttribute("password", user.Password);
                root.AppendChild(xe);
                doc.Save(AppDomain.CurrentDomain.BaseDirectory + "file\\UserInfor.xml");
                message = "添加成功";
                return true;
            }
            else
            {
                message = "用户已存在";
                return false;
            }
        
      
        }
}
}
这个你只需要定义一个userserver对象,你就可以调用相应的方法,这样做不仅可以减少冗余的代码而且看起来相当清晰,调试也方便。在这个类中,你可以看到三种方法:检验登录是否成功的方法,密码修改的方法,还有添加用户的方法。
namespace lesson
{
    class view
    {   //mDocument代表XML文件,mCurrentNode表示选择好的节点。
        public XmlDocument mDocument;
      
        public bool addcondition(yaoinfor yao)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(AppDomain.CurrentDomain.BaseDirectory + "yaogan.xml");
            XmlNode root = doc.DocumentElement;
            XmlNode target = root.SelectSingleNode(string.Format("//message[@times='{0}']", yao.Times));
            if (target == null)
            {
                XmlElement xe = doc.CreateElement("message");
                xe.SetAttribute("times",yao.Times);
                xe.SetAttribute("condition", yao.Conditions);
                root.AppendChild(xe);
                doc.Save(AppDomain.CurrentDomain.BaseDirectory + "yaogan.xml");
                //message = "添加成功";
                return true;
            }
            else
            {
               // message = "记录已存在";
                return false;
            }
        }
        public bool disp(ref Listcondis ,ref string message)
        {
            XmlDocument doc = new XmlDocument();
            //List condis = new List();
            view vies = new view();
            yaoinfor yaoconditions = new yaoinfor();
            doc.Load(AppDomain.CurrentDomain.BaseDirectory + "yaogan.xml");
            XmlNode root = doc.DocumentElement;
            try
            {
                foreach (XmlNode item in root.ChildNodes)
                {
                    XmlElement xe = (XmlElement)item;
                    switch (item.Name)
                    {
                        case "times": yaoconditions.Times = xe.GetAttribute("times"); break;
                        case "condition": yaoconditions.Conditions = xe.GetAttribute("condition"); break;
                        default: break;
                    }
                    condis.Add(yaoconditions);
                }
                return true;
            }
            catch
            {
                return false;
            }
           
        }
        public void CreatXmlDocument() //建立新的文件   
        {
            mDocument = new XmlDocument();
            //定义XML文档头文件
            XmlDeclaration xmlDeclaration = mDocument.CreateXmlDeclaration("1.0", "utf-8", null);
            //增加XML文档头
            mDocument.AppendChild(xmlDeclaration);
            //定义XML的根
            XmlElement xmlRoot = mDocument.CreateElement("Modbus");
            //添加XML的根
            mDocument.AppendChild(xmlRoot);
            //添加根的属性
            xmlRoot.SetAttribute("Version", "1.00.00");
           // XmlElement newtimes = mDocument.CreateElement("times");
            //XmlElement newcondition = mDocument.CreateElement("condition");
            //XmlText times = mDocument.CreateTextNode(DateTime.Now.ToString());
            //XmlText conditions = mDocument.CreateTextNode(yaoin.Conditions);
            //newtimes.AppendChild(times);
            //newcondition.AppendChild(conditions);
            //添加XML根的节点
            //xmlRoot.AppendChild(newtimes);
            //xmlRoot.AppendChild(newcondition);
            // Save the document to a file.
            mDocument.Save("yaogan.xml");
        }
        //public  void ReadXmlDocument() //读取Xml文件
        //{
        //    XmlElement xmlRoot = mDocument.DocumentElement;
        //    //使用SelectSingleNode查找到想要的参数
        //    mCurrentNode = xmlRoot.SelectSingleNode("times");
        //    comboBox1.Text = mCurrentNode.InnerText;
        //}
        //public void SaveXmlDocument() //保存Xml文件
        //{
        //    //XmlElement xmlRoot = mDocument.DocumentElement;
        //    ////使用SelectSingleNode查找到想要的参数,
        //    //mCurrentNode = xmlRoot.SelectSingleNode("times");
        //    //mCurrentNode.InnerText = comboBox1.Text;
        //  mDocument.Save("ModbusIni.xml");
        //}
    }
}
这些代码都是在一个类中的,这次开发这个软件我所实现的方法都编写在相应的类中,感觉用起来相当方便,调试时也很方便,如果结果没出来,你只需要进入相应的类方法中调试就行,不会干扰其他代码。对于多人合作相当方便,各自只需要把自己要做的软件模块写成对应的类方法。整合组装在一起就行而不需要知道对方的进度或代码是如何编写的。这次就不截图了,感觉图形截了好多次了。如果要看软件实物,我已经上传了,可以去下载、https://bbs.eeworld.com.cn/thread-341313-1-1.html
有些细心的网友可能看到我保存数据用的是XML格式,可能会问为何不用数据库呢?主要是考虑到大伙基本是搞电子的,好多是没安装数据库。而用这个就不需要安装什么了,只要打开软件就可以对数据进行处理,很方便。其次是因为我当时在搞ASP.NET做网站,当时就弄.XML所以就用个了这个。

回复评论 (13)

顶啊,
点赞  2012-7-28 13:36
把串口的代码也共享一下就好了
点赞  2012-7-28 13:37

顶起

http://shop34182318.taobao.com/ https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
点赞  2012-7-28 13:41

回复 板凳 luhuaneda2 的帖子

既然是DIY,我可以把串口代码分享的。晚上在这个帖子里贴出来
点赞  2012-7-28 15:25
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
using System.Xml;
namespace lesson
{
    public partial class SComAssistant : Form
    {
        SerialPort sp = new SerialPort();
        bool isOpen=false;
        bool isSetProperty = false;
        public SComAssistant()
        {
            InitializeComponent();
        }
        public delegate void HandleInterfaceUpdataDelegate(string text);
        private HandleInterfaceUpdataDelegate interfaceUpdataHandle;
        
       private void SComAssistant_Load(object sender, EventArgs e)
        {

            SerialPort.GetPortNames();
            this.MinimumSize = this.Size;
            //this.MinimizeBox = false;
            for (int i = 0; i < 20; i++)
            {
                cbxComPort.Items.Add("COM" + (i + 1).ToString());


            }
            cbxComPort.SelectedIndex = 2;
            cbxBaudRate.Items.Add("300");
            cbxBaudRate.Items.Add("600");
            cbxBaudRate.Items.Add("1200");
            cbxBaudRate.Items.Add("2400");
            cbxBaudRate.Items.Add("4800");
            cbxBaudRate.Items.Add("9600");
            cbxBaudRate.Items.Add("19200");
            cbxBaudRate.Items.Add("38400");
            cbxBaudRate.Items.Add("43000");
            cbxBaudRate.Items.Add("56000");
            cbxBaudRate.Items.Add("57600");
            cbxBaudRate.Items.Add("115200");
            cbxBaudRate.SelectedIndex = 5;
            cbxStopBits.Items.Add("0");
            cbxStopBits.Items.Add("1");
            cbxStopBits.Items.Add("1.5");
            cbxStopBits.Items.Add("2");
            cbxStopBits.SelectedIndex = 1;
            cbxParity.Items.Add("无");
            cbxParity.Items.Add("奇检验");
            cbxParity.Items.Add("偶检验");
            cbxParity.SelectedIndex = 0;
            cbxDataBits.Items.Add("8");
            cbxDataBits.Items.Add("7");
            cbxDataBits.Items.Add("6");
            cbxDataBits.Items.Add("5");
            cbxDataBits.SelectedIndex = 0;
            
            
        }

      

      public void sp_DataReceived(object sender,  System.IO.Ports.SerialDataReceivedEventArgs e)
        {  byte[] readBuffer = new byte[sp.ReadBufferSize];  
            sp.Read(readBuffer, 0, readBuffer.Length);
            this.Invoke(interfaceUpdataHandle, new string[] { Encoding.UTF8.GetString(readBuffer)});
         
        
     }  
      


      
      

        private void btnCheckCom_Click(object sender, EventArgs e)
        {
            //检测哪些串口有用
            cbxComPort.Items.Clear();
            for (int i = 0; i <20; i++)
            {
                try
                {
                    SerialPort sp = new SerialPort("COM"+(i+1).ToString());
                    //sp.DiscardNull = true;
                    sp.Open();
                    sp.Close();
                    cbxComPort.Items.Add("COM" + (i + 1).ToString());
                    //sp_DataReceived();
                    MessageBox.Show("COM" + (i + 1).ToString() + "可用");
                }


                catch (Exception)
                {
                    //lblStatus.Text = "COM" + (i + 1).ToString() + "不可用";
                    //MessageBox.Show("COM" + (i + 1).ToString() + "不可用","错误提示");
                    continue;
               
               
                }
            
            
            }

        }
        private bool CheckPortSetting ()
        {
       //自己填写,其实很简单的            
        }

        private bool CheckSendData()
        {
            if (tbxSendData.Text.Trim() == "")
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        private void SetPortProperty()
        { //设置串口属性
            
            sp.PortName = cbxComPort.Text.Trim();//设置串口名
            //设置串口波特率
            sp.BaudRate = Convert.ToInt32(cbxBaudRate.Text.Trim());
            //设置串口停止位
            float f = Convert.ToSingle(cbxStopBits.Text.Trim());
            if (f == 0)
            {
                sp.StopBits = StopBits.None;

            }
            else if (f == 1)
            {
                sp.StopBits = StopBits.One;
            }
            else if (f == 1.5)
            {
                sp.StopBits = StopBits.OnePointFive;

            }
            else if (f == 2)
            {
                sp.StopBits = StopBits.Two;

            }
            else
            {
                sp.StopBits = StopBits.One;


            }
            //设置数据位
            sp.DataBits = Convert.ToInt16(cbxDataBits.Text.Trim());
            //设置奇偶检验位
            string s = cbxParity.Text.Trim();
            if (s.CompareTo("无") == 0)
            {
                sp.Parity = Parity.None;
            }
            else if (s.CompareTo("奇检验") == 0)
            {
                sp.Parity = Parity.Odd;

            }
            else if (s.CompareTo("偶检验") == 0)
            {
                sp.Parity = Parity.Even;
            }
            else
            {
                sp.Parity = Parity.None;
            }
            //设置超时读取时间
            sp.ReadTimeout = -1;
            //打开串口
            try
            {
                sp.Open();
                isOpen = true;
            }
            catch (Exception)
            {

                lblStatus.Text = "打开串口时发生错误!";

            }

        }


        private void btnSendData_Click(object sender, EventArgs e)
        {
           //发送数据
            
            if (!CheckPortSetting())
            {
                MessageBox.Show("设置没有串口!","错误提示");
                return;
            
            }
            if (!CheckSendData())
            {
                MessageBox.Show("请输入要发送的数据!", "错误提示");
                return;
            
            }
            if (!isSetProperty)
            {
                SetPortProperty();
                isSetProperty = true;
            
            }
            if(isOpen)
            {
                //写串口数据
                try
                {
                    sp.Write(tbxSendData.Text);
                }
                catch(Exception )
                {
                    lblStatus.Text = "发送数据时错误!";
                    //lblStatus.Text =ex.Message;
                    return;
                  
               
                }
            
            }
            else
            {
                MessageBox.Show("串口未打开!","错误提示");
                //goto lal;
            }
            

        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            try
            {
                sp.Close();
                MessageBox.Show("欢迎您下次再次使用");
                //this.Close();
            }
            catch (Exception)
            {
                MessageBox.Show("最好不要不做任何操作就关闭串口助手","错误提示");
               // this.Close();
            }

        }

      
        private void btnRecvData_Click(object sender, EventArgs e)
        {
            getrecvdata();
        }
      
        public void getrecvdata()
        {
            if (!isSetProperty)
            {
                SetPortProperty();
                isSetProperty = true;

            }

            try
            {
                if (isOpen)
                {
                    //C#串口监听之实例化委托对象
                    interfaceUpdataHandle = new HandleInterfaceUpdataDelegate(UpdateTextBox);
                    sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
                    sp.ReceivedBytesThreshold = 1;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
               
            }
        
        }

            
    }
}
这个就是C#串口的代码,你可以看到里面有些是调用了我自己写的类方法,很方便。其实这次串口本来也可以抽取出来定义成类方法,但是没弄,下次在做项目时就把串口重新抽取出来。其实最好的代码就是你看不到实现过程只需要调用API就可以了。我没有把所有的都公布,主要是我想分享的不是代码,这样类似的代码网上很多,我只是想分享些自己DIY过程中所获得一些心得,如果把代码给你们,就是COPY一下,有什么用?别人的代码仅仅就是借鉴下,自己写出的代码才是最好的代码,哪怕语法有问题,也是自己的。别人的再好如果不能吸收,对自己来说也没半点用处。希望有兴趣的朋友可以自己试下,不懂可以发帖提问。感觉好的心得分享不是说我的代码可以运行,你就COPY去运行下,好的心得经验应该是一条可以复制的成功路线,就像唐骏的我的成功可以复制一样。最后说一句,如果真心想弄串口的朋友,最好自己编写下代码,只有自己写了才会真正懂得为什么要这样写,那样写就不行,我记得在串口接收数据时就用richtext这个控制去接受数据,当时虽然接受到了,但是我需要的是前四个数据(0x01)所以我需要把接受的数据的长度求出来用for语言取出来,本来按理来说是可以的,但是我调试时就出现了遇到\0它竟然没有终止,我当时我郁闷,怎么办呢?它就是那个样子,但是你又拿它没办法,问题摆在那,你总的解决吧?于是我想到了用一个字符串类型的变量接受那个文本控件的内容,也用length就成功了,如果我不做的话,我就会以为文本控件的类型也字符串的一样,可以那样做,但实际却不行。好多问题,感觉最好自己亲自走一遍才会真正体会到里面的道理。

[ 本帖最后由 wateras1 于 2012-7-28 20:03 编辑 ]
点赞  2012-7-28 19:36
mark之
点赞  2012-7-29 19:51
点赞  2012-7-30 09:00
看到这个帖子https://bbs.eeworld.com.cn/viewth ... page%3D1#pid1371822
好奇,看了一下楼主发过的主题帖子

没仔细看代码
密码一般还是哈希加密一下好?类的可访问性不声明默认是什么来着?应该是约束较严的一种吧?不允许程序集以外使用?

.net虽然容易上手,开发工具也可以,不过毕竟和电子是两码事,所以,如果不是个别情况,对于普遍来说还是做自己的专业比较好,毕竟什么都不是那么专业简单的,当然有时间有精力的另当别论了,多了解一些东西说不准什么时候会大有好处,但是这个可能也说不准了。
没工作,没女人老婆,没宽带 ,  没钱
点赞  2012-9-3 16:44

回复 9楼 wangfuchong 的帖子

因为这个项目不是做成产品所以做的很一般,好多东西都很随意,加密也没加。默认为内部类internal,类只能在当前项目中访问。呵呵,我学的很杂,PCB,驱动,上位机软件都学过,光计算机语言目前流行的都搞过,目前主要就是使用.NET。驱动也主攻ARM。PCB就基本不搞了,有时间自己瞎鼓捣下。马上要找工作了,想多搞也没时间。只有以后慢慢全面加强自己了
点赞  2012-9-4 13:15
楼主多面手呀,原来专业是什么?现在专业类型是什么呀?
没工作,没女人老婆,没宽带 ,  没钱
点赞  2012-9-4 15:38

回复 11楼 wangfuchong 的帖子

嵌入式系统开发,现在准备搞驱动开发
点赞  2012-9-5 00:55
学习学习学习
点赞  2012-11-6 23:05

回复 楼主 wateras1 的帖子

楼主帮我看看这个:
这个监控界面的功能如下:
1、接收CAN和以太网传输的数据并显示;
2、根据相关数据进行相应的控制,实现“四遥”功能;
3、部分数据能够以柱状图的形式表示;
4、数据显示时,界面刷新速度小于200ms
5、数据量比较大
6、生成可执行文件后,打包后的文件会不会更大?
点赞  2012-12-26 09:29
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复