等待线程完成而不阻止UI线程

时间:2017-12-29 14:18:15

标签: c# multithreading winforms

我正在编写winForm个应用程序,它必须是SerialPort,并将数据实时打印到多行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,打开小错误窗口并告诉我请检查设置(因此根据我的代码捕获InvalidOperationException);如果我不使用{ {1}}并删除backgoundWorker程序启动会显示从端口接收的数据但阻止用户界面。任何想法都会非常有用。

1 个答案:

答案 0 :(得分:1)

button4_click需要调用backgroundWorker1.CancelAsync()而不是设置bool。对于BackgroundWorkers,您需要指定希望它们结束然后检查它,设置和检查外部bool将不起作用。 backgroundWorker1_DoWork()方法中的try块应如下所示。请注意,如果您重命名变量(在U​​I中完成或右键单击变量并选择'重命名'),您和其他人就可以更轻松地为您提供帮助。在代码之前的另一个注释,使用' goto'几乎总是没有问题,几乎总有一个更好的选择(在这种情况下是一个while循环)。

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");
    }
}

编辑说:这应该让你开始,你也想看看this link从backgroundWorker1访问你的用户界面,问题是你的UI在一个线程上而你的BackgroundWorker在另一个线程上,线程没有没有一些赞美代码就能很好地协同工作