c#System.InvalidOperationException

时间:2013-03-14 13:31:08

标签: c# asynchronous tcp client

常规

我正在尝试在C#中编写一个非常简单的TCPIP客户端服务器以连接到具有端口号的IP地址,并询问非常简单的行命令,然后将回复放在网格箱,图形或其他显示选项中

我已经在网上找到了一个可以下载的实用程序,由Jayan Nair编写,这似乎正确地发送消息,并且收到回复确定。

当我尝试将回复数据加载到richtext或GridView时出现问题。

我得到的错误信息是: - System.InvalidOperationException

我问过微软论坛,他们给了我一个非常复杂,含糊不清和过度参与的关于我应该做什么的指示,这涉及一些名为INVOKE和BeginInvoke的东西,而且他们整个事情似乎都是一个项目自己的权利。

我所追求的只是一个有效的例子,而不是太复杂。

这是代码: -

        try
        {
            SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
            int iRx = theSockId.thisSocket.EndReceive(asyn);
            char[] chars = new char[iRx + 1];
            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
            // 
            System.String szData = new System.String(chars);
            richTextRxMessage.Text =  szData;  // fails
            //textBox1.Text = szData;          // also fails
            WaitForData();
        }

,这是错误消息: -

base {System.Windows.Forms.TextBoxBase} = {Text = '((System.Windows.Forms.RichTextBox)    (((System.Windows.Forms.RichTextBox)(richTextRxMessage)))).Text' threw an exception of type   'System.InvalidOperationException'}

其他信息包括: - szData包含大约6300个字符,包括制表符(9)和返回(13),并且与服务器发送的消息一致 我也尝试使用文本框而不是richtext,结果相同

感兴趣的人

这是Microsoft链接

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/12a67fb0-847e-4e2b-baa8-ef6ceed60aa4/


  • 这里只是我尝试过的两个代码修改,两个都在相同的错误条件下失败
  • 我认为我需要做的是以更低的水平开始C#,而不仅仅是跳进去,希望最好的


       public void OnDataReceived(IAsyncResult asyn)
        {
    
            int InputRx;
            int charLen;
            char[] Inputchars;
            System.Text.Decoder InputDecode;
            System.String szData;
            bool IfInvokeRequired;
    
            try
    
            {
    
                SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
                InputRx = theSockId.thisSocket.EndReceive(asyn);                    // get size of input array
                Inputchars = new char[InputRx + 1];                                   // put i char array
                InputDecode = System.Text.Encoding.UTF8.GetDecoder();
                charLen = InputDecode.GetChars(theSockId.dataBuffer, 0, InputRx, Inputchars, 0);
                szData = new System.String(Inputchars);
                IfInvokeRequired = richTextRxMessage.InvokeRequired;
                if (IfInvokeRequired == true)
                {
                    richTextRxMessage.Invoke((MethodInvoker)delegate { this.Text = szData; });// fails
                    richTextRxMessage.BeginInvoke(new MethodInvoker(() => richTextRxMessage.Text = szData));//fails as well
                }
    
  • 4 个答案:

    答案 0 :(得分:5)

    您收到的InvalidOperationException可能会有内部异常“调用线程无法访问此对象,因为其他线程拥有它”。

    为了便于调试,您可以快速将CheckForIllegalCrossThreadCalls设置为false。这将阻止运行时抛出异常,但仅仅因为你没有收到异常并不意味着它们没有发生,所以这对于分布式软件来说是一种不好的做法,但是非常方便调试。

    为了解决您的问题,您需要调用与 UI Thread 上的RichTextBox交互的代码,即创建控件的线程,以及允许的唯一线程运行与控件交互的代码。

    要调用UI线程上的代码,您可以使用以下简洁的语句:

    richTextRxMessage.BeginInvoke(new MethodInvoker(() => richTextRxMessage.Text = szData));
    

    很简单,你在这里所做的就是通过委托传递你想在UI线程上调用的语句。

    答案 1 :(得分:1)

    这是我在我的一些东西中使用的函数;

    public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
    {
        if (@this.InvokeRequired)
        {
            @this.Invoke(action, new object[] { @this });
        }
        else
        {
            action(@this);
        }
    }
    

    这对于处理任何类型的调用来说都是一个很好的小方法,并且当你使用它时会减少代码行。要使用它,只需使用它;

    Control.InvokeEx(f => control.DoStuff());
    

    例如,您可以使用;

    richTextRxMessage.InvokeEx(f => richTextRxMessage.Text =  szData);
    

    编辑:正如其他人所说的那样,这个错误很可能是由于访问了一个不是创建它的线程的控件,这就是为什么需要调用。

    答案 2 :(得分:0)

    微软的答案并非完全不正确,但还有其他方法可以做到这一点,虽然他们看起来不那么简单。

    这是我自己的代码中的一个snippit,可能会派上用场。

    if (dirtyImage.InvokeRequired)
    {
        dirtyImage.Invoke(new MethodInvoker(delegate { Visible = RigX.IsDirty; }));
        dirtyImage.Invoke(new MethodInvoker(delegate { Refresh(); }));
    }
    else
    {
        dirtyImage.Visible = RigX.IsDirty;
        dirtyImage.Refresh();
    }
    

    注意InvokeRequireddirtyImage.Invoke(...)的使用方式。通过创建委托和使用方法调用程序,我可以更简单,这样我就可以将所有调用都设置为一个衬里。委托实际上创建了一个迷你方法,然后使用MethodInvoker调用该方法。因为更改是在UI线程上,所以不使用.Invoke从后台线程调用它们,不允许使用它。

    以这种方式改变你的电话的方式是:

    richTextRxMessage.Invoke(new MethodInvoker(delegate { Text =  szData; }));
    

    该调用也直接来自UI线程本身,所以你实际上并不需要if语句,但是它的条件是'cost',它比直接调用属性慢。

    当然,如果您在后台线程上开始,这只会产生影响。如果没有,那么您需要调查错误本身。也许返回文本有问题,将其写入文件并查看它,看看是否可以发现问题。尝试手动设置RTB的文本,看看它是否允许这种情况发生。等等等。

    答案 3 :(得分:0)

    问题可能是因为MS论坛上建议的多线程。当您以异步方式请求此操作时,它将创建另一个将处理输入的线程,以便您的主应用程序线程不会阻塞。

    要解决此问题,您必须Invoke您希望更改其属性的控件。你需要这个,因为你的主应用程序线程拥有UI,并且UI上的任何操作都不能从另一个线程完成。

    调用并不复杂,可以在几行中完成。

    更改以下行

    richTextRxMessage.Text =  szData;
    

    richTextRxMessage.Invoke((MethodInvoker) delegate {this.Text = szData;});
    

    此代码将要求主ui线程更新richTextRxMessage的文本,而不是自行完成。