当我接收数据时,c#阻塞了表单

本文关键字:表单 数据 | 更新日期: 2023-09-27 18:17:30

我有arduino uno和我使用它像A/D转换器。到我的arduino信号1-5V,我将其转换为数字并将其发送到我的端口。我用c#编写了一个应用程序。下面是应用程序的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace na_posla
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            button1.Enabled = true;
            button2.Enabled = false;
            button3.Enabled = false;
            getAvailablePorts();
        }
        void getAvailablePorts()
        {
            String[] ports = SerialPort.GetPortNames();
            comboBox1.Items.AddRange(ports);
        }
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
        }
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (comboBox1.Text == "" || comboBox2.Text == "")
                {
                    MessageBox.Show("Please select port settings");
                }
                else
                {
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
                    serialPort1.Open();
                    progressBar1.Value = 100;
                    button1.Enabled = false;
                    button2.Enabled = true;
                    button3.Enabled = true;
                }
            }
            catch (UnauthorizedAccessException)
            {
                textBox1.Text = "Unauthorized Access";
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            progressBar1.Value = 0;
            textBox1.Text = "";
            button1.Enabled = true;
            button2.Enabled = false;
            button3.Enabled = false;
        }
        private void button3_Click(object sender, EventArgs e)
        {
            double y = 0;
            double doubleval;
            string stringVal;
            stringVal = serialPort1.ReadLine();
            if (stringVal.Contains("."))
                stringVal = stringVal.Replace(".", ",");
            doubleval = System.Convert.ToDouble(stringVal);
            y = (doubleval / 5) * 40;

            textBox1.Text = y.ToString();
            //for (; ; )
            //{
            //    stringVal = serialPort1.ReadLine();
            //    if (stringVal.Contains("."))
            //        stringVal = stringVal.Replace(".", ",");
            //    doubleval = System.Convert.ToDouble(stringVal);
            //    y = (doubleval / 5) * 40;

            //    textBox1.Text = y.ToString();
            //}

        }
     }
}

在表单中,我有2个组合框,3个按钮,进度条和文本框。按钮1打开端口按钮,按钮2关闭端口按钮。当我按下按钮3(读)我从arduino接收数据,我写在文本框中。当我有这个代码,我点击阅读我收到新的数据。当我想在循环中读取数据时,问题就开始了。在代码中,循环被注释。我不能点击任何按钮,我不能停止阅读。我读过背景工作者,但我不知道如何在我的代码中应用它。有人能帮帮我吗?

当我接收数据时,c#阻塞了表单

你必须使用一个线程来读取(我希望我在代码中没有忘记什么):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace na_posla
{
    public partial class Form1 : Form
    {
        Thread readThread = null;
        bool threadCanRun = false;
        public Form1()
        {
            InitializeComponent();
            button1.Enabled = true;
            button2.Enabled = false;
            button3.Enabled = false;
            getAvailablePorts();
        }
        void getAvailablePorts()
        {
            String[] ports = SerialPort.GetPortNames();
            comboBox1.Items.AddRange(ports);
        }
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
        }
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (comboBox1.Text == "" || comboBox2.Text == "")
                {
                    MessageBox.Show("Please select port settings");
                }
                else
                {
                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
                    serialPort1.Open();
                    progressBar1.Value = 100;
                    button1.Enabled = false;
                    button2.Enabled = true;
                    button3.Enabled = true;
                }
            }
            catch (UnauthorizedAccessException)
            {
                textBox1.Text = "Unauthorized Access";
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            progressBar1.Value = 0;
            textBox1.Text = "";
            button1.Enabled = true;
            button2.Enabled = false;
            button3.Enabled = false;
        }
        private void button3_Click(object sender, EventArgs e)
        {
            StopReadThread();
            StartReadThread();
        }
        private void SetTextBoxText(TextBox txtBox, string value)
        {
            if (txtBox.InvokeRequired)
            {
                txtBox.Invoke((MethodInvoker)delegate { SetTextBoxText(txtBox, value); });
                return;
            }
            txtBox.Text = value;
        }
        private void StartReadThread()
        {
            if (readThread == null)
                readThread = new Thread(ReadDataLooped);
            if (readThread.ThreadState == ThreadState.Unstarted)
            {
                threadCanRun = true;
                readThread.Start();
            }
        }
        private void StopReadThread()
        {
            if(readThread != null && readThread.ThreadState != ThreadState.Unstarted)
            {
                if (readThread.IsAlive)
                {
                    threadCanRun = false;
                    Thread.Sleep(50);
                    readThread.Abort();
                    readThread.Join();
                }
            }
        }
        private void ReadDataLooped(object obj)
        {
            try
            {
                while (threadCanRun)
                {
                    ReadAndSetData();
                    Thread.Sleep(1000); //Wait a second between the reads
                }
            }
            catch (ThreadAbortException)
            {
                Thread.ResetAbort();
            }
        }
        private double ReadValueFromSerialPort()
        {
            string stringVal = serialPort1.ReadLine();
            if (stringVal.Contains("."))
                stringVal = stringVal.Replace(".", ",");
            double doubleval = System.Convert.ToDouble(stringVal);
            double y = (doubleval / 5) * 40;
            return y;
        }
        private void ReadAndSetData()
        {
            this.SetTextBoxText(textBox1, this.ReadValueFromSerialPort().ToString());
        }
    }
}

解释:

表单在应用程序的STAThread中运行。如果你想做一些工作,你的线程被阻塞,因为工作已经完成。因此,如果你想永久更新数据,你必须在一个单独的线程中运行这段代码,UI可以在第一个STAThread中更新和响应。有很多方法可以做到这一点。我决定使用一个简单的Thread,因为它是。net 3.5兼容的。任务和等待从。net 4.0开始实现(并且更容易/更少的工作)。