c#串口程序界面卡死问题

作者:超级管理员 更新时间:2017-09-13 09:58:10 来源:未知 点击:15642
 private void sp_DataReceived(object sender,SerialDataReceivedEventArgs e)        {            Syste
 private void sp_DataReceived(object sender,SerialDataReceivedEventArgs e)
        {
            System.Threading.Thread.Sleep(100); //延时100ms等待接收完数据
            //this.Invoke就是跨线程访问ui的方法
            this.Invoke((EventHandler)(delegate
            {
                if (isHex == false)
                {
                    tbxRecvData.Text += sp.ReadLine();
                }
                else
                {
                    Byte[] ReceivedData = new Byte[sp.BytesToRead];  //创建接收字符数组
                    sp.Read(ReceivedData, 0, ReceivedData.Length);
                    String RecvDataText = null;
                    for (int i = 0; i < ReceivedData.Length - 1; i++)
                    {
                        RecvDataText += ("0x" + ReceivedData[i].ToString("X2") + "");
                    }
                    tbxRecvData.Text += RecvDataText;
                }
                sp.DiscardInBuffer(); //丢弃接收缓冲区数据
            }));
        }

好像是这段代码哪里的问题导致界面卡死
大佬们看一下帮忙改一下

以下是关于本问题的解决方案:

解决方案1、
System.Threading.Thread.Sleep(100); //延时100ms等待接收完数据
这句要少用。
我说下我的思路:

DataReceived 这个方法之外应该有一个变量去储存每时每刻获取到的下位机数据。
监视该变量,委托+事件去处理数据。
最后,数据处理完毕Invoke 匿名委托去填充窗体控件。
说的不对请参考。
解决方案2、
依据什么判断定100ms 数据接收完毕?使用this.invoke 可以,因为DataReceived 由其它线程执行,而textbox创建隶属UI线程。 
不要用sleep,而应该尽可能的在“处理接收数据”上下功夫,也就是接收的数据不应该用sleep 来堆积到缓冲区,而是由程序来进行顺序处理,使用线程安全的ConcurrentQueue来接收并处理数据。
解决方案3、
        private void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] data = new byte[sp.BytesToRead];
            sp.Read(data, 0, data.Length);
            sp.DiscardInBuffer();
            UpdateTextBox(texRev, Encoding.Default.GetString(data));
        }

 private void UpdateTextBox(TextBox sender, string content)
        {
            this.Invoke((EventHandler) delegate
            {
                sender.AppendText(content + ++num + Environment.NewLine);
            });
        }

解决方案4、
简单编写测试,没有问题,可以正常发送接收



using System;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;

namespace COMTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private SerialPort sp = new SerialPort();

        private void btnOpen_Click(object sender, EventArgs e)
        {
            sp.PortName = "COM2";
            sp.BaudRate = 9600;
            sp.DataBits = 8;
            sp.StopBits = StopBits.One;
            sp.Parity = Parity.None;
            sp.ReadTimeout = 1000;
            sp.ReceivedBytesThreshold = 1;
            if (!sp.IsOpen)
                sp.Open();

            sp.DataReceived += Sp_DataReceived;
            btnOpen.Enabled = false;
        }

        private void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] data = new byte[sp.BytesToRead];
            sp.Read(data, 0, data.Length);
            sp.DiscardInBuffer();
            UpdateTextBox(texRev, Encoding.Default.GetString(data));
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            byte[] data = Encoding.Default.GetBytes(texData.Text);
            sp.Write(data, 0, data.Length);
        }
        private void UpdateTextBox(TextBox sender, string content)
        {
            this.Invoke((EventHandler) delegate
            {
                sender.AppendText(content + Environment.NewLine);
            });
        }
    }
}

解决方案5、
例如像 RecvDataText += ("0x" + ReceivedData[i].ToString("X2") + ""); 这种代码,以及前边几行代码,根本不操作UI 控件,那么根本不应该放到 Invoke 中。而且只是一般地临时显示的话,使用 BeginInvoke 显然比 Invoke 更好。

你在阻塞 UI 线程(Invoke它)的时候,你执行  sp.ReadLine(); 这样的代码,这个 ReadLine 本身就是卡死、死等、阻塞式的代码,要等待对方传来换行回车或者文件结束符号才能解除阻塞。显然这样编程设计是不合适的。

尤其是通讯程序, 要处理粘包、分包概念,更不应该阻塞式 Readline。
解决方案6、
我使用BeginInvoke,还是要卡死,我该怎么改了这段代码呢

推荐阅读

热门内容

关于对文件名使用 string.Repl

这里我用replace()想要让文件名变...

wpf的keydown事件

页面只有这句话       ...

ASP.NET MVC验证表单

代码如下        [Require...

EasyUi Datagrid+Deta

各位牛人,有没有做过类似的功能效果,Ea...

c#串口程序界面卡死问题

 private void sp_Dat...

C# 判断一张图片是否是空白图片

平时做文件扫描存档,一般都是双面扫描.扫...

我在Winform中修改WebBrows

我在Winform中修改WebBrows...

c# 引用webservice 出现问题

我在浏览器浏览没问题就是在项目中添加服务...

有人这么黑易语言,连我都看不下去了

本帖最后由caozhy于2017-09-...

窗体加载时,代码未执行完就弹出了窗体

不知道是这样写不合理,还是我哪里写错了呢...

最新内容

关于对文件名使用 string.Replace() 没有作用 请教

这里我用replace()想要让文件名变成E:\CloudMusic\薛之谦 -...

以下代码实现的单例模式有什么缺陷?如果有,请做出你的修改!

public sealed class Singleton       stat...

wpf的keydown事件

页面只有这句话         

ASP.NET MVC验证表单

代码如下        [Required(ErrorMessage = "标题...

以XX开头的标识符太长,最大长度为128

本帖最后由qz6412525于2017-09-1212:09:14编辑如题,是一...

分部声明包含冲突的可访问性修饰符

代码如下:namespace ConstDefinitionLib{    pu...

关于 查询语句 中select 索引问题

string[] fruits = { "apple", "banana", "...

EasyUi Datagrid+DetailView 如何让他默认全部展开

各位牛人,有没有做过类似的功能效果,EasyUI DataGrid+Detail...

c#串口程序界面卡死问题

 private void sp_DataReceived(object sen...

浏览器内核问题

请问有谁会使用vs2013,用c#或vb编写在winform里面嵌一个谷歌浏览器...

LINQ to Entities 不识别方法“System.DateTime AddMinutes(Double)”,因此该方法无法转换为存储表达式。

代码如下,求大神帮忙看看:                    DateTim...

mvc 怎么执行mysql里的存储过程

我的连接是这样的。 public class mysqlconn : DbCon...

C# 判断一张图片是否是空白图片

平时做文件扫描存档,一般都是双面扫描.扫描之后,需要存档,有些背面空白的,需要剔...

我在Winform中修改WebBrowser控件修改User-Agent的方法貌似对WebkitBrowser无效,我已经修改为手机了

我在Winform中修改WebBrowser控件修改User-Agent的方法貌...

RawSocket抓包时,如果是正在传文件,则丢包严重的吓人

50M的文件传输,只抓到100-200KB。public void Run() ...

如何让Toast占满整个屏幕(包含状态栏)

本帖最后由sixsun1989于2017-09-1221:15:38编辑    ...

不熬夜看这里 苹果发布会直播全程回顾

        想必今天一早醒来,你的朋友圈和新闻头条一定都会被昨晚科技圈的大事...

网友心声有求必应 苹果同传四川话版

         在苹果秋季发布会开始前两周,我们针对网友喜欢听什么地方方言做过...

iPhone X演示出重大失误?背后另有真相

    中关村在线消息:苹果公司于美国西部时间9月12日上午10点(北京时间9月...

全视曲面商务旗舰 三星Note 8今晚发布

    中关村在线消息: 备受大家期待的三星新旗舰Note 8将于今晚18时在北...