Multithreading 在Windows窗体C+中通过线程传递参数+/CLI

Multithreading 在Windows窗体C+中通过线程传递参数+/CLI,multithreading,winforms,arguments,c++-cli,Multithreading,Winforms,Arguments,C++ Cli,我真的很难做一些很简单的事情。基本上,我正在尝试编写一个Windows Form C++/CLI程序,从串行端口读取arduino流,并至少在最初将每个值添加到列表框中。Arduino代码还可以,它每2秒给我一个字符串,当我调试带有断点的Windows窗体时,我可以看到字符串变量“Message”的值很好地输入。但是我遇到了这个“线程”问题,我知道我必须创建一个不同的线程来更新列表框。。。好啊现在,我找不到一种方法将“message”字符串传递给函数“UpdateList”。我见过很多关于传递对

我真的很难做一些很简单的事情。基本上,我正在尝试编写一个Windows Form C++/CLI程序,从串行端口读取arduino流,并至少在最初将每个值添加到列表框中。Arduino代码还可以,它每2秒给我一个字符串,当我调试带有断点的Windows窗体时,我可以看到字符串变量“Message”的值很好地输入。但是我遇到了这个“线程”问题,我知道我必须创建一个不同的线程来更新列表框。。。好啊现在,我找不到一种方法将“message”字符串传递给函数“UpdateList”。我见过很多关于传递对象、类等的事情。。。但我无法将其放入我的代码中。有人能帮忙吗

完整代码如下:

#pragma once

namespace ArduComm {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Threading;

public ref class MyForm : public System::Windows::Forms::Form
{
public:
    MyForm(void)
    {
        InitializeComponent();
    }

protected:
    ~MyForm()
    {
        if (components)
        {
            delete components;
        }
    }

private: System::IO::Ports::SerialPort^  Arduino;
private: System::Windows::Forms::Button^  StartButton;
private: System::Windows::Forms::Button^  StopButton;
private: System::Windows::Forms::ListBox^  ListBox;
private: System::ComponentModel::IContainer^  components;

#pragma region Windows Form Designer generated code

    void InitializeComponent(void)
    {
        this->components = (gcnew System::ComponentModel::Container());
        this->Arduino = (gcnew System::IO::Ports::SerialPort(this->components));
        this->StartButton = (gcnew System::Windows::Forms::Button());
        this->StopButton = (gcnew System::Windows::Forms::Button());
        this->ListBox = (gcnew System::Windows::Forms::ListBox());
        this->SuspendLayout();
        // 
        // Arduino
        // 
        this->Arduino->PortName = L"COM3";
        this->Arduino->DataReceived += gcnew System::IO::Ports::SerialDataReceivedEventHandler(this, &MyForm::ArduinoDataReceived);
        // 
        // StartButton
        // 
        this->StartButton->Location = System::Drawing::Point(12, 12);
        this->StartButton->Name = L"StartButton";
        this->StartButton->Size = System::Drawing::Size(75, 23);
        this->StartButton->TabIndex = 3;
        this->StartButton->Text = L"Start";
        this->StartButton->UseVisualStyleBackColor = true;
        this->StartButton->Click += gcnew System::EventHandler(this, &MyForm::StartReadingSerial);
        // 
        // StopButton
        // 
        this->StopButton->Location = System::Drawing::Point(12, 41);
        this->StopButton->Name = L"StopButton";
        this->StopButton->Size = System::Drawing::Size(75, 23);
        this->StopButton->TabIndex = 4;
        this->StopButton->Text = L"Stop";
        this->StopButton->UseVisualStyleBackColor = true;
        this->StopButton->Click += gcnew System::EventHandler(this, &MyForm::StopReadingSerial);
        // 
        // ListBox
        // 
        this->ListBox->FormattingEnabled = true;
        this->ListBox->Location = System::Drawing::Point(117, 12);
        this->ListBox->Name = L"ListBox";
        this->ListBox->Size = System::Drawing::Size(273, 277);
        this->ListBox->TabIndex = 5;
        // 
        // MyForm
        // 
        this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
        this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
        this->ClientSize = System::Drawing::Size(409, 303);
        this->Controls->Add(this->ListBox);
        this->Controls->Add(this->StopButton);
        this->Controls->Add(this->StartButton);
        this->Name = L"MyForm";
        this->Text = L"ArduComm";
        this->ResumeLayout(false);

    }
#pragma endregion

/* My functions */


private: System::Void UpdateList() {
    ListBox->Items->Add("xxx");
}

private: System::Void InvokeThread()    {
    this->Invoke(gcnew MethodInvoker(this, &MyForm::UpdateList));
}

private: System::Void ArduinoDataReceived(System::Object^ sender, System::IO::Ports::SerialDataReceivedEventArgs^ e) {
    String^ Message;
    Message = Arduino -> ReadLine();
    Thread^ oThread = gcnew Thread(gcnew ThreadStart(this, &MyForm::InvokeThread));
    oThread->Start();
}

private: System::Void StartReadingSerial(System::Object^  sender, System::EventArgs^  e) {
    this->Arduino->Open();
}

private: System::Void StopReadingSerial(System::Object^  sender, System::EventArgs^  e) {
    this->Arduino->Close();
}

};
}
任何帮助都将不胜感激

谢谢。

不要启动线程。SerialPort::DataReceived事件处理程序已在工作线程上运行,添加另一个线程不会产生任何效果。您需要编写一个可以从事件处理程序调用的方法,它应该如下所示:

    void UpdateList(String^ message) {
        ListBox->Items->Add(message);
    }
现在,您需要声明一个与此方法兼容的委托,这是您忽略的一个关键步骤,是什么让您陷入困境:

    delegate void UpdateListDelegate(String^ Message);
也可以使用内置的
操作
泛型类型。现在,您可以从事件处理程序调用它。使用BeginInvoke()非常重要,当您关闭串行端口时,使用Invoke()有很高的死锁可能性:

    System::Void Arduino_DataReceived(System::Object^  sender, System::IO::Ports::SerialDataReceivedEventArgs^  e) {
        String^ message = Arduino->ReadLine();
        this->BeginInvoke(gcnew UpdateListDelegate(this, &MyForm::UpdateList), message);
    }

哇,汉帕桑先生。你给我的代码工作得很好,尽管我不完全理解它。我首先启动线程的原因是,在尝试了最简单的方法(将消息添加到DataReceived函数内的列表框)后,我收到一条错误消息,说“线程之间的操作无效…从线程访问的控件…不是创建它的线程”,我能找到的每个解决方案都告诉我应该开始一个新的线程。老实说,所有这些“线程”、“委托”和“调用”的东西对我来说都是全新的。我想是时候在这些方面再深入一点了!!非常感谢您花时间提供帮助!