“跨线程操作无效”..在读取串口数据时出现

3
在一个Windows窗体应用程序中,在主窗体加载时,我设置了一个串口并开始读取它。目的是,当我在串口上接收到一些数据时,我想打开与数据相关的另一个窗体。
因此,我使用串口的DataReceived事件处理程序。
  void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {

            string str = this.serialPort1.ReadLine();


                if (!string.IsNullOrEmpty(str))
                {


                    Main.Instance.customerData = new CustomerData(str);
                    Main.Instance.customerData.MdiParent = Main.Instance;  //Exeption received at this point
                    Main.Instance.customerData.Disposed += new EventHandler(customerData_Disposed);

                    Main.Instance.customerData.Show();


                }

        }

但是当我尝试在事件处理程序中打开一个表单时,它会给我一个InvalidOperationExeption错误,显示:"跨线程操作无效:从创建它的线程以外的线程访问控件'Main'。"
我尝试删除代码行:Main.Instance.customerData.MdiParent = Main.Instance;,然后它可以正常工作。但是为了将其作为子窗体打开,也需要分配mdiparent。
有什么建议来解决这个问题吗?
3个回答

2

使用Invoke方法在主窗体上进行操作。您需要将控制权移交给主窗体以与其交互。事件处理程序在后台线程上触发。

以下是可能有效的示例代码:

void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string str = this.serialPort1.ReadLine();
    if (!string.IsNullOrEmpty(str))
    {
        ShowCustomerData(str);
    }   

}

private delegate void ShowCustomerDataDelegate(string s);

private void ShowCustomerData(string s)
{
    if (Main.Instance.InvokeRequired)
    {
        Main.Instance.Invoke(new ShowCustomerDataDelegate(ShowCustomerData), s);
    }
    else
    {

        Main.Instance.customerData = new CustomerData(str);
        Main.Instance.customerData.MdiParent = Main.Instance;  //Exeption received at this point
        Main.Instance.customerData.Disposed += new EventHandler(customerData_Disposed);

        Main.Instance.customerData.Show();
    }
}

谢谢David。我会尝试学习Invoke方法,因为我从未使用过它。 - Marshal

1

这是因为 Windows 中的线程法则很简单,就是 "除了 UI 线程,不得从任何其他线程访问 UI"

所以您需要使用 Control.Invoke 在 UI 线程上运行访问 UI 的代码。

//assuming your within a control and using C# 3 onward..
this.Invoke( () =>
 {
   //anything that UI goes here.
 }
);

稍微Stackoverflow忍者谷歌搜索一下就能帮到你了。这是一个相当臭名昭著的问题。

这个答案似乎几乎完全符合你的问题: 在监听COM端口时无效的跨线程操作


谢谢Giddy.. 是的,我尝试过谷歌搜索,但由于我不知道线程,所以我试图寻找更简单的解决方案,如果有的话...但我认为我必须学习线程和调用方法 :) - Marshal
1
@Niraj,这并不是太复杂了。任何一本涵盖线程的C#书籍都会告诉你我在第一行提到的内容(事实上,那是来自Addison Wesley的一本书=P)。只要记住,每当您异步访问UI(从另一个线程)时,您需要使用invoke切换回主UI线程。这也适用于WPF和Silverlight,那里称为dispatcher。 - gideon

1

您的事件处理程序未在UI线程上运行。要进入UI线程,请使用主窗体的Invoke方法。


谢谢Richard。我会尝试学习Invoke方法,因为我从未使用过它。 - Marshal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接