串口应用线程委托实现界面交互的操作方法

1、构建方法时候,需要用界面来显示串口接收到的数据,所以我才用了,较为复杂的委托事件线程的方法,把串口接收的模块并入到我的主工程中;

总结一下串口模块的设计,

 

新建一个委托

public delegate void SerialPortEventHandler(Object sender, SerialPortEventArgs e);

新建一个事件 SerialPortEventArgs类,继承自事件数据的类的基类

public class SerialPortEventArgs : EventArgs
{
public bool isOpend = false;
public Byte[] receivedBytes = null;
}

新建一个ComModel类

   在类中申明事件

    public event SerialPortEventHandler comReceiveDataEvent = null;
    public event SerialPortEventHandler comOpenEvent = null;
    public event SerialPortEventHandler comCloseEvent = null;

    

     private SerialPort sp = new SerialPort();

     private Object thisLock = new Object();

 

    在串口控件的事件中,有3个事件

                             

当串口接收到数据时,触发 DataReceived 事件, 单击产生的方法中加入代码功能:

  1.假如 sp.BytesToRead <= 0 ,返回。

  2.锁住线程  lock (thisLock)

  3.读取数据:  

1                 int len = sp.BytesToRead;
2                 Byte[] data = new Byte[len];
3                 try
4                 {
5                     sp.Read(data, 0, len);
6                 }                

  4.new出来自己定义的事件 SerialPortEventArgs 

      SerialPortEventArgs args = new SerialPortEventArgs(); 

       事件中传送的数据

     args.receivedBytes = data;

   5.如果 事件comReceiveDataEvent ,不为空,则用事件......()

    if (comReceiveDataEvent != null)
    {
      comReceiveDataEvent.Invoke(this, args);
    }

     //用事件通知界面

 新建一个IController的类

 

  Controller类是Form类和Model类的桥梁,在该Controller中,将界面上的更新函数注册到Model中。
  

    public class IController
    {
        ComModel comModel = new ComModel();
        IView view;

        public IController(IView view)
        {
            this.view = view;
            view.SetController(this);
            //将页面上的更新界面函数注册到Model的事件
            comModel.comCloseEvent += new SerialPortEventHandler(view.CloseComEvent);
            comModel.comOpenEvent += new SerialPortEventHandler(view.OpenComEvent);
            comModel.comReceiveDataEvent += new SerialPortEventHandler(view.ComReceiveDataEvent);
        }
    }

 

一般来说Controller比较复杂的一部分,但在这个程序中比较简单,没有数据库相关的操作。

  

在界面层

  声明一个接口  IView,并在mainform中引用这个接口   “public partial class FormMain : Form,IView

  public interface IView
  { 

  void ComReceiveDataEvent(Object sender, SerialPortEventArgs e);

  }

编写串口接收事件函数

public void ComReceiveDataEvent(object sender, SerialPortEventArgs e)
{

          //
          // 摘要:
          //     获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
          //
          // 返回结果:
          //     如果控件的 System.Windows.Forms.Control.Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为
          //     true;否则为 false。
            if (this.InvokeRequired)
            {
                try
                { //
                  // 摘要:
                  //     在拥有控件的基础窗口句柄的线程上,用指定的参数列表执行指定委托。
                  //
                  // 参数:
                  //   method:
                  //     一个方法委托,它采用的参数的数量和类型与 args 参数中所包含的相同。
                  //
                  //   args:
                  //     作为指定方法的参数传递的对象数组。如果此方法没有参数,该参数可以是 null。
                  //
                  // 返回结果:
                  //     System.Object,它包含正被调用的委托返回值;如果该委托没有返回值,则为 null。
                    Invoke(new Action<Object, SerialPortEventArgs>(ComReceiveDataEvent), sender, e);
                }
                catch (System.Exception)
                {
                    //disable form destroy exception
                }
                return;
            }
            if (true) //字符串display as string
            {
                receivetbx.AppendText(Encoding.Default.GetString(e.receivedBytes));
                receiveBytesCount += e.receivedBytes.Length;
                acceptStatusLabel.Text = "Received: " + receiveBytesCount.ToString();
            }

 

}

 

posted @ 2018-01-12 18:38  Ecr_hool  阅读(502)  评论(0编辑  收藏  举报