当我接收数据时,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接收数据,我写在文本框中。当我有这个代码,我点击阅读我收到新的数据。当我想在循环中读取数据时,问题就开始了。在代码中,循环被注释。我不能点击任何按钮,我不能停止阅读。我读过背景工作者,但我不知道如何在我的代码中应用它。有人能帮帮我吗?
你必须使用一个线程来读取(我希望我在代码中没有忘记什么):
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开始实现(并且更容易/更少的工作)。