2016-12-03 8 views
-2

Я бы отслеживал данные, полученные в последовательном порту с моим компьютером и Arduino. На ардуине эскиз посылает на USB-порт строку «aabb» evry 300ms. С ПК я хочу слушать, а в режиме реального времени печатать строку в элементе управления (Textbox). Для этого я создаю новый поток, который прослушивает цикл, который поступает в последовательный порт, и когда это происходит, пишите с помощью Invoke строки в текстовом поле. Процедуры работают, если я развертываю в классе формы, но если я использую внешний класс, это не так. Чтобы лучше объяснить этот вопрос, я вставить код классаПочему Invoke не работает в другом классе

class SerialPortManager 
{ 
    public SerialPort Serial = new SerialPort(); 
    private Thread thr; 
    private string Log; 
    public TextBox textLog; 
    public string LastString; 
    public bool thrIsAlive; 
    [Browsable(false)] 
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
    [EditorBrowsable(EditorBrowsableState.Advanced)] 
    [IODescriptionAttribute("ControlInvokeRequiredDescr")] 
    public bool InvokeRequired { get; private set; } 

    //DISPOSE 
    public void Dispose() 
    { 
     this.Dispose(); 
    } 

    //SET Textobox LOG 
    public void SetLogTxtB (TextBox txt) 
    { 
     textLog = txt; 
    } 

    //PORTE DISPONIBILI 
    public string[] Available_Ports() 
    { 
     return SerialPort.GetPortNames(); 
    } 

    //COSTRUTTORI 
    public SerialPortManager(string portname, int baudrate,bool InitializeConn) 
    { 
     Serial.BaudRate = baudrate; 
     Serial.PortName = portname; 
     if (InitializeConn == true) Serial.Open(); 
    } 
    public SerialPortManager() 
    { 

    } 

    //SETTA I PARAMETRI E INIZIALIZZA LA CONNESSIONE 
    public void SetConnectionParam(string portname, int baudrate, bool initializeConn) 
    { 
     Serial.Close(); 
     Serial.Dispose(); 
     Serial = new SerialPort(); 
     Serial.BaudRate = baudrate; 
     Serial.PortName = portname; 
     if (initializeConn == true) Serial.Open(); 
    } 

    //ASYNC LISTENER 
    public void AsyncListener() 
    { 
     thrIsAlive = true; 
     thr = new Thread(ThreadReader); 
     thr.Start(); 
    } 
    //PROCEDURA PER APPEND 
    public void AppendTextBox(string value) 
    { 
     if (InvokeRequired) 
     { 
      this.Invoke(new Action<string>(AppendTextBox), new object[] { value }); 
      return; 

     } 
     textLog.Text += value; 
    } 

    private void Invoke(Action<string> action, params object[] v) 
    { 
     throw new NotImplementedException(); 
    } 

    void ThreadReader() 
    { 
     while (thrIsAlive) 
     { 
      string temp = Serial.ReadLine(); 
      LastString = temp; 
      Log += LastString + "\n"; 
      AppendTextBox(LastString + "\n"); 
     } 

    } 
} 

В форме я пишу три строки

SerialPortManager PortMan = new Driver_Arduin.SerialPortManager("COM3", 9600,true); 
     PortMan.SetLogTxtB(textBox1); 
     PortMan.AsyncListener(); 

Если я пытаюсь запустить программу, возвращает ошибку "операция кросс-нить не позволил". Теперь, когда я отправляю это спросить, я решил сделать последнюю попытку и изменить метод AppendTextBox на:

public void AppendTextBox(string value) 
    { 
     if (textLog.InvokeRequired) 
     { 
      try 
      { 
       textLog.Invoke(new Action<string>(AppendTextBox), new object[] { value }); 
       return; 
      } 
      catch (ObjectDisposedException) 
      { 
       thrIsAlive = false; 
      } 
     } 
     textLog.Text += value; 
    } 

И наконец работает. Теперь выяснилось, что Power Stackoverflow решил проблему до публикации, я бы знал, почему работает мой код. Спасибо

ответ

0

В SerialPortManager вы должны использовать делегат вместо управления окнами.

class SerialPortManager 
    { 
     public SerialPort Serial = new SerialPort(); 
     private Thread thr; 
     private string Log; 
     //public TextBox textLog; 
     public Action<string> textLog; 
..... 

Крит в Вас форме просто метод:

public void SetTextBoxText(string value) 
    { 
     if (textBox1.InvokeRequired) 
     { 
      try 
      { 
       textBox1.Invoke(new Action<string>(AppendTextBox), new object[] { value }); 
       return; 
      } 
      catch (ObjectDisposedException) 
      { 
       thrIsAlive = false; 
      } 
     } 
     textBox1.Text += value; 
    } 

Набор делегата для Портман:

SerialPortManager PortMan = new Driver_Arduin.SerialPortManager("COM3", 9600,true); 
     PortMan.SetLogTxtB=new Action<string>(SetTextBoxText); 
     PortMan.AsyncListener(); 

Если выход необходимо войти в TextBox из Портман называют textLog делегата.

void ThreadReader() 
    { 
     while (thrIsAlive) 
     { 
      string temp = Serial.ReadLine(); 
      LastString = temp; 
      Log += LastString + "\n"; 
      //AppendTextBox(LastString + "\n"); 
      textLog(LastString + "\n"); 
     } 

    } 
0

Кроме того ваш метод Invoke в SerialPortManager должен бросить NotImplementedException проблема заключается в том, что вы определили свой собственный InvokeRequired/Invoke.

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

На самом деле кажется, что вы можете использовать ваш SerialPortManager но использовать InvokeRequired/Invoke из textLog, как вы уже делаете в AppendTextBox.

BTW, if (initializeConn == true) довольно бесполезно - if (initializeConn) достаточно.