Непрерывное чтение последовательного порта с несколькими событиями - PullRequest
0 голосов
/ 19 октября 2018

Я новичок в C # и ищу несколько советов по проблеме, которую я пытался решить в своем приложении Windows Form.

У меня есть приложение, которое должно непрерывно считывать данные, возвращающиеся в программу через подключенный последовательный порт.У меня есть кнопки, которые открывают и закрывают порт через пользователя.У меня возникают проблемы при настройке обработчика событий «DataReceived» для чтения входящих данных и отображения их в текстовом поле в приложении.

Я получаю эту ошибку: «Недопустимая операция между потоками: доступ к элементу управления textBox4 осуществляется из потока, отличного от потока, в котором он был создан».Я вижу, что это ошибка потока, но я не смог выяснить мою проблему.

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

        private void getAvailabePorts()
        {
            String[] ports = SerialPort.GetPortNames();
            comboBox1.Items.AddRange(ports);
        }
        public void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (comboBox1.Text == "" || comboBox2.Text == "")
                {
                    textBox4.Text = "Please select port settings";
                }
                else
                {

                    serialPort1.PortName = comboBox1.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
                    serialPort1.DataReceived += new SerialDataReceivedEventHandler(mySerialPort_DataReceived);

                    serialPort1.Open();
                }
            }
            catch (UnauthorizedAccessException)
            {
                textBox4.Text = "Unauthorized Access";
            }

            public void mySerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                SerialPort sp = (SerialPort)sender;
                textBox4.Text = sp.ReadExisting() + "\n";
            }

            private void button2_Click(object sender, EventArgs e)
            {
                serialPort1.Close();

                textBox4.Clear();
            }

        }
    }
}

1 Ответ

0 голосов
/ 20 октября 2018

Во-первых, добро пожаловать.

Перед «большой» проблемой (сортировка данных), позвольте мне предупредить вас - последовательные порты хитры.Например, ваш вызов «ReadExisting» может не вернуть того, что вы ожидаете, - он вернет все, что находится в буфере последовательного порта во время , но может появиться больше, что перезапишет то, что уже находится в вашемтекстовое окно.Так что вы можете добавить данные вашего текстового поля.

Теперь реальная проблема.Как уже упоминалось, комментатор не может публиковать данные из другой ветки непосредственно в ветке пользовательского интерфейса.Без вашего ведома, последовательный порт создал новый поток для получения данных.

Вы можете справиться с этим напрямую, изменив код получателя следующим образом:

    public void mySerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        SerialPort sp = (SerialPort) sender;
        var dataRcvd = sp.ReadExisting();
        object[] dataArray = new object[1];
        dataArray[0] = dataRcvd;
        BeginInvoke( new postDataDelegate( postData), dataArray );
    }

    private delegate void postDataDelegate( string d );
    private void postData( string d) 
    {
        textBox4.Text = d;
    }

Это «маршаллизирует» данныев поток пользовательского интерфейса, чтобы его можно было использовать.Есть много способов сделать это (и есть много различий между тем, как это делается в WPF и Winforms, так что следите за этим).Я надеюсь, что это иллюстрирует эту мысль.

Еще одно замечание - нет необходимости делать метод DataReceived общедоступным - он будет отлично работать в частном порядке.

...