TheJoKr Channel Ответов: 1

Почему кнопки перестают работать после запуска таймера?


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;


namespace Arduino
{
    public partial class Form1 : Form
    {
        bool arduinoConnected;
        bool hazardMode;
        string[] msgSplit;
        string msg;
        public Form1()
        {
            InitializeComponent();
        }
       
        private void btnConnect_Click(object sender, EventArgs e)
        {
            if (arduinoConnected == false)
            {
                serialPort.Open();
                btnConnect.BackColor = Color.Green; 
                btnConnect.Text = "Disconnect";
                arduinoConnected = true;
                timer.Start();
            }
            else
            {
                serialPort.Close();
                btnConnect.Text = "Connect";
                btnConnect.BackColor = Color.Red;
                arduinoConnected = false;
                hazardMode = false;
                lbUpdates.Items.Add("Alarm Off");
                btnAlarm.BackColor = Color.Green;
                timer.Stop();
            }
        }

        private void btnAlarm_Click(object sender, EventArgs e)
        {
            if (serialPort.IsOpen)
            {
                if (hazardMode == false)
                {
                    hazardMode = true;
                    
                    serialPort.Write("HazardOn\n");
                    lbUpdates.Items.Add("Alarm On");
                    btnAlarm.BackColor = Color.Red;
                }
                else
                {
                    serialPort.Write("HazardOff\n");
                    hazardMode = false;
                    lbUpdates.Items.Add("Alarm Off");
                    btnAlarm.BackColor = Color.Green;
                }
            }
            else
            {
                MessageBox.Show("Please turn on the car first", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void timer_Tick(object sender, EventArgs e)
        {
            if (arduinoConnected)
            {
                lbUpdates.SelectedIndex = lbUpdates.Items.Count - 1;
                lbUpdates.SelectedIndex = -1;
                msg = serialPort.ReadLine().Trim();
                if (msg.StartsWith("Temp"))
                {
                    msgSplit = msg.Split(':');
                    tbTemp.Text = msgSplit[1];
                }
                else if (msg.StartsWith("Light"))
                {
                    msgSplit = msg.Split(':');
                    tbLights.Text = msgSplit[1];
                    if (msgSplit[1] == "ON")
                        tbLights.Text = "Headlights on";
                    else if (msgSplit[1] == "OFF")
                        tbLights.Text = "Headlights off";
                }
                else if (msg.StartsWith("LeftBlink"))
                {
                    msgSplit = msg.Split(':');
                    if (msgSplit[1] == "ON")
                        lbUpdates.Items.Add("Left Blink On");
                    else if (msgSplit[1] == "OFF")
                        lbUpdates.Items.Add("Left Blink Off");
                }
                else if (msg.StartsWith("RightBlink"))
                {
                    msgSplit = msg.Split(':');
                    if (msgSplit[1] == "ON")
                        lbUpdates.Items.Add("Right Blink On");
                    else if (msgSplit[1] == "OFF")
                        lbUpdates.Items.Add("Right Blink Off");
                }
            }
        }
    }
}


Что я уже пробовал:

Я поиграл с интервалами таймера и заставил его работать, как только интервал был >5000, но проблема в том, что я получаю задержанную обратную связь, и мне нужно, чтобы она была мгновенной...

CHill60

Вероятно, потому, что вы ждете ввода от порта в потоке пользовательского интерфейса. Это должно происходить на заднем плане. Вот серия статей, которые помогут вам начать работу Руководство для начинающих по нарезанию резьбы в .NET: Часть 1 из n[^]

TheJoKr Channel

Но почему проблема исчезает, как только я устанавливаю интервал в 5000?
Спасибо за комментарий кстати

CHill60

Вероятно, потому, что к тому времени буфер заполняется, поэтому ReadLine больше не блокируется - см. решение @OriginalGriff

1 Ответов

Рейтинг:
8

OriginalGriff

ReadLine - это блокирующий вызов-если во входном буфере последовательного порта нет полной строки, он не будет возвращаться до тех пор, пока она не появится. Поскольку ваш таймер активен в потоке пользовательского интерфейса, это означает, что весь ваш пользовательский интерфейс не может делать ничего другого, пока этот вызов не вернется.

Вы вообще не должны обрабатывать входные данные с "медленного устройства" (а последовательные порты обычно очень медленные) в потоке пользовательского интерфейса - что является одной из причин того, что событие "получить доступные данные" автоматически запускается в другом потоке.

Я бы предложил развернуть поток BackgroundWorker для обработки ваших данных SerialPort и передавать завершенные сообщения обратно в поток пользовательского интерфейса через механизм отчетов о ходе выполнения ИТ-операций.