C# 等待线程完成而不阻塞UI线程
我正在编写C# 等待线程完成而不阻塞UI线程,c#,multithreading,winforms,C#,Multithreading,Winforms,我正在编写winForm应用程序,它必须列出mSerialPort,并将数据实时打印到多行textbox 代码如下: using System; using System.Drawing; using System.Windows.Forms; using System.IO.Ports; using System.Threading; using System.ComponentModel; namespace SCPListener { public partial class F
winForm
应用程序,它必须列出mSerialPort
,并将数据实时打印到多行textbox
代码如下:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.ComponentModel;
namespace SCPListener
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
GetAvailablePortNames();
panel1.BackColor = ColorTranslator.FromHtml("#f44147");
cbDefaultValue();
}
String[] PortNames;
bool conn = true;
String data;
public string datetime;
Form2 frm = new Form2();
void GetAvailablePortNames()
{
PortNames = SerialPort.GetPortNames();
comboBox1.Items.AddRange(PortNames);
}
void RefreshAvailablePortNames()
{
comboBox1.Items.Clear();
PortNames = SerialPort.GetPortNames();
comboBox1.Items.AddRange(PortNames);
}
public string getDataTime()
{
DateTime time = DateTime.Now;
string date = time.ToString(@"hh\:mm\:ss");
return date;
}
public void GetData()
{
string date = getDataTime();
data = serialPort1.ReadLine();
textBox1.AppendText("[" + date + "] " + "Received: " + data + "\r\n");
}
public void cbDefaultValue()
{
comboBox1.SelectedIndex = 0;
comboBox5.SelectedIndex = 0;
comboBox2.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
comboBox4.SelectedIndex = 0;
}
private void button1_Click(object sender, EventArgs e)
{
try
{
if (comboBox1.Text == "" || comboBox2.Text == "" || comboBox3.Text == "" || comboBox4.Text == "" || comboBox5.Text == "")
{
MessageBox.Show("Please port settings", "Incorrect port settings", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
DateTime time = DateTime.Now;
string date = time.ToString(@"hh\:mm\:ss");
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
switch (comboBox3.Text)
{
case "5":
serialPort1.DataBits = 5;
break;
case "6":
serialPort1.DataBits = 6;
break;
case "7":
serialPort1.DataBits = 7;
break;
case "8":
serialPort1.DataBits = 8;
break;
default:
serialPort1.DataBits = 5;
break;
}
switch (comboBox4.Text)
{
case "None":
serialPort1.Parity = Parity.None;
break;
case "Odd":
serialPort1.Parity = Parity.Odd;
break;
case "Even":
serialPort1.Parity = Parity.Even;
break;
case "Mark":
serialPort1.Parity = Parity.Mark;
break;
case "Space":
serialPort1.Parity = Parity.Space;
break;
}
switch (comboBox5.Text)
{
case "One":
serialPort1.StopBits = StopBits.One;
break;
case "Two":
serialPort1.StopBits = StopBits.Two;
break;
case "OnePointFive":
serialPort1.StopBits = StopBits.OnePointFive;
break;
}
serialPort1.Open();
string CurrentPornName = comboBox1.Text;
label7.Text = "Opened " + CurrentPornName;
panel1.BackColor = ColorTranslator.FromHtml("#42f477");
comboBox1.Enabled = false;
comboBox2.Enabled = false;
comboBox3.Enabled = false;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
//button5.Enabled = false;
//button6.Enabled = false;
}
}
catch (Exception ex)
{
if (ex is UnauthorizedAccessException)
{
MessageBox.Show("Unauthorized Acces","Access Error",MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ex is System.IO.IOException)
{
MessageBox.Show("Please plug in your device", "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void button2_Click(object sender, EventArgs e)
{
panel1.BackColor = ColorTranslator.FromHtml("#f44147");
string CurrentPornName = comboBox1.Text;
label7.Text = "Closed " + CurrentPornName; ;
serialPort1.Close();
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
//button5.Enabled = true;
//button6.Enabled = true;
}
private void button5_Click(object sender, EventArgs e)
{
RefreshAvailablePortNames();
}
private void button3_Click(object sender, EventArgs e)
{
//backgroundWorker1.RunWorkerAsync();
Thread thread = new Thread(start: ()=>
{
try
{
datetime = getDataTime();
string date = getDataTime();
startListening:
if (serialPort1.BytesToRead > 0)
{
datetime = getDataTime();
data = serialPort1.ReadLine();
textBox2.AppendText("[" + datetime + "] " + "Received: " + data + "\r\n");
}
else
textBox2.AppendText("[" + datetime + "] " + "Error: There is no data to read" + "\r\n");
if (conn)
goto startListening;
}
catch (Exception ex)
{
DateTime time = DateTime.Now;
string date = time.ToString(@"hh\:mm\:ss");
if (ex is TimeoutException)
{
textBox1.AppendText("[" + date + "] " + "Timuot Exception" + "\r\n");
}
else if (ex is InvalidOperationException)
{
MessageBox.Show("Plese check settings", "Error: Invalid Operation", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ex is System.IO.IOException)
{
MessageBox.Show("Port opened, but device unpluged..", "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
});
thread.Start();
}
private void button4_Click(object sender, EventArgs e)
{
conn = false;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
datetime = getDataTime();
string date = getDataTime();
startListening:
if (serialPort1.BytesToRead > 0)
{
datetime = getDataTime();
data = serialPort1.ReadLine();
textBox2.AppendText("[" + datetime + "] " + "Received: " + data + "\r\n");
}
else
textBox2.AppendText("[" + datetime + "] " + "Error: There is no data to read" + "\r\n");
if (conn)
goto startListening;
}
catch (Exception ex)
{
DateTime time = DateTime.Now;
string date = time.ToString(@"hh\:mm\:ss");
if (ex is TimeoutException)
{
textBox1.AppendText("[" + date + "] " + "Timuot Exception" + "\r\n");
}
else if (ex is InvalidOperationException)
{
MessageBox.Show("Plese check settings", "Error: Invalid Operation", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ex is System.IO.IOException)
{
MessageBox.Show("Port opened, but device unpluged..", "IO Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}
关于代码:
comboBox1 -> where the Ports are listed
comboBox2 -> where the Baud Rates options are listed
comboBox3 -> where the Stop Bits options are listed
comboBox4 -> where the Data Bits options are listed
comboBox5 -> where the Parity options are listed
button1 -> to connect chosen port
button2 -> to disconnect port
button3 -> to start listening and print data into textBox in real time
button4 -> to stop listening
button5 -> refresh available ports
panel1-> to identify port is connected or not (if connected it is green if it is not connected it is red)
所以,我想做的是,当我点击停止按钮(button4
)时,程序必须停止监听。我正试图使用backgroundWorker
实现这个结果。
当我尝试侦听端口时使用此代码(单击开始按钮
button3
会打开小错误窗口,并告知请检查设置(因此它会根据我的代码捕获invalidooperationexception
);如果我不使用backgoundWorker
并删除请尝试{…}cath{…}
程序启动确实显示从端口接收到的数据,但会阻塞UI。任何想法都会非常有用。按钮4\u单击需要调用backgroundWorker1.CancelAsync()不要设置bool。对于BackgroundWorkers,您需要指定希望它们结束,然后检查它,设置和检查外部bool将不起作用。backgroundWorker1_DoWork()中的try块方法应该如下所示。请记住,如果重命名变量(在UI中完成,或者通过右键单击变量并选择“重命名”),您和其他人会更容易帮助您。代码之前的另一个注意事项是,使用“goto”几乎从来都不好,几乎总是有更好的选项(在本例中是while循环)
编辑为:这应该让您开始,您还需要签出以从BackgroundWorker访问您的UI 1,问题是您的UI在一个线程上,而您的BackgroundWorker在另一个线程上,如果没有一些补充代码,线程无法很好地协同工作您最好先重命名变量(组合框和按钮):)您知道您可以重命名控件并为其指定描述性名称吗?这样就不需要为代码提供密钥了。@zcui93在本例中没有任何意义:)。建议您先阅读。请珍惜他人的时间。抛开命名约定不谈,简而言之,您应该使用工作线程并决定如何结束它。您可以优雅地关闭线程,或者只是中止它并忽略异常。这取决于你。关于优雅地关闭线程,有很多文章和答案。另一方面,为什么要使用if(con)goto而不是在一段时间内包装它(con)?:)谢谢,我已经编辑了这段代码,但是现在出现了跨线程错误。
datetime = getDataTime();
string date = getDataTime();
while (!backgroundWorker1.CancellationPending)
{
if (serialPort1.BytesToRead > 0)
{
datetime = getDataTime();
data = serialPort1.ReadLine();
textBox2.AppendText($"[{datetime}] Received: {data}\r\n");
}
else
{
textBox2.AppendText($"[{datetime}] Error: There is no data to read\r\n");
}
}