简体   繁体   English

c#System.InvalidOperationException

[英]c# System.InvalidOperationException

General 一般

I'm trying to write a very simple TCPIP client server in C# to connect to an IP Address, with a port number, and ask quite simple line commands, and then place the replies in a Gridbox, graph or other display option. 我正在尝试在C#中编写一个非常简单的TCPIP客户端服务器来连接到具有端口号的IP地址,并询问非常简单的行命令,然后将回复放在网格箱,图形或其他显示选项中。

I have looked online and found a down loadable utility that does just this, written by Jayan Nair, and this appears to send the message correctly, and receive the reply ok. 我已经在网上找到了一个可以下载的实用程序,由Jayan Nair编写,这似乎正确地发送消息,并收到回复确定。

The problem comes when I try and load the reply data into a richtext or GridView. 当我尝试将回复数据加载到richtext或GridView时出现问题。

The error message I'm getting is :- System.InvalidOperationException 我得到的错误消息是: - System.InvalidOperationException

I have asked Microsoft Forums, and they have given me a very complicated, ambiguous and overly involved indication as to what I should do, and this involves something called INVOKE and BeginInvoke, and they whole things seems to be a project in it;s own right. 我问过微软论坛,他们给了我一个非常复杂,含糊不清和过度参与的关于我应该做什么的指示,这涉及一些名为INVOKE和BeginInvoke的东西,而且他们整个事情似乎都是一个项目;它自己对。

What I'm after is just an example that works, without being too complicated. 我所追求的只是一个有效的例子,而不是太复杂。

Here's the code :- 这是代码: -

        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();
        }

and here's the error message :- 这是错误信息: -

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

Additional information is :- szData contains about 6300 characters, including tabs (9) and returns (13), and is consistant with the message sent from the server I've also tried it with using a textbox instead of richtext, same result 附加信息是: - szData包含大约6300个字符,包括制表符(9)和返回(13),并且与服务器发送的消息一致我也尝试使用文本框而不是richtext,结果相同

For those interested 对于那些感兴趣

Here's the Microsoft link 这是Microsoft链接

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


  • Here is just 2 of the code amendments that I've tried, both fail on the same error condition 这里只是我尝试过的两个代码修改,两个都在相同的错误条件下失败
  • I think what I need to do is start C# at a much lower level and not just jump in and hope for the best 我认为我需要做的是以更低的水平开始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 } 
  • The InvalidOperationException that you receive will likely have the inner exception " The calling thread cannot access this object because a different thread owns it ". 您收到的InvalidOperationException可能会有内部异常“ 调用线程无法访问此对象,因为另一个线程拥有它 ”。

    For the sake of debugging you can quickly set CheckForIllegalCrossThreadCalls to false. 为了便于调试,您可以快速将CheckForIllegalCrossThreadCalls设置为false。 This will stop the run-time from throwing you an exception, however just because you're not receiving the exceptions does not mean that they are not happening so this is a bad practice for distributed software but very handy for debugging. 这将阻止运行时抛出异常,但仅仅因为您没有收到异常并不意味着它们没有发生,所以这对于分布式软件来说是一种不好的做法,但是非常方便调试。

    In order to resolve your issue you need to invoke the code that interacts with the RichTextBox on the UI Thread aka the thread the control was created on and the only thread that is allowed to run code that interacts with the control. 为了解决您的问题,您需要调用与UI Thread上的RichTextBox交互的代码,也就是创建控件的线程,以及允许运行与控件交互的代码的唯一线程。

    To invoke the code on the UI Thread you can use the following, succinct statement: 要调用UI线程上的代码,您可以使用以下简洁的语句:

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

    Very simply, all you are doing here is passing the statement you wish to invoke on the UI Thread by means of a delegate. 很简单,您在这里所做的就是通过委托传递您希望在UI线程上调用的语句。

    Here's a function I use in some of my stuff; 这是我在一些东西中使用的函数;

    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);
        }
    }
    

    It's pretty much a nice little method for dealing with any sort of invoke, and cuts down the lines of code when you're using it. 它是处理任何类型调用的一个很好的小方法,并在您使用它时减少代码行。 To use it, simply use this; 要使用它,只需使用它;

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

    So for example, you might use; 例如,您可以使用;

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

    Edit: As others have said, this error is more than likely due to accessing a control on a thread other than the one it was created on, which is why the invokes are required. 编辑:正如其他人所说,这个错误很可能是由于访问了一个不是创建它的线程上的控件,这就是为什么需要调用。

    The Microsoft answer is not entirely incorrect, but there are other ways to do it that are somewhat simpler, although they dont look it. 微软的回答并不完全错误,但还有其他方法可以做到这一点,虽然他们看起来不太简单。

    Here is a snippit from my own code that might come in handy for you. 这是我自己的代码中的一个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();
    }
    

    note how InvokeRequired and the dirtyImage.Invoke(...) are used. 注意如何使用InvokeRequireddirtyImage.Invoke(...) I make it a lot simpler by creating the delegates and using a method invoker, that way I can make all the calls one liners. 通过创建委托和使用方法调用程序,我可以更简单,这样我就可以将所有调用都设置为一个衬里。 the delegate essentially creates a mini-method, which is then invoked using the MethodInvoker. 委托实际上创建了一个迷你方法,然后使用MethodInvoker调用该方法。 Because the changes are on the UI thread though, they cannot be called from a background thread without using .Invoke , its not permitted. 因为更改是在UI线程上,但是不使用.Invoke能从后台线程调用它们,不允许这样做。

    The way your calls could be altered in this way is: 以这种方式改变你的电话的方式是:

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

    that call also works directly from the UI thread itself, so you dont actually NEED the if statement, but it terms of 'cost', its slower than calling the properties directly. 该调用也直接来自UI线程本身,所以你实际上并不需要if语句,但是它的条件是'cost',它比直接调用属性慢。

    Of Course, this only really makes a difference if you were on a background thread to begin with. 当然,如果您在后台线程开始时,这只会产生重大影响。 If not, then you need to investigate the error itself. 如果没有,那么您需要调查错误本身。 Perhaps there is something wrong with the text of the return, write it to a file and look at it, see if you can spot the problem. 也许返回文本有问题,将其写入文件并查看它,看看是否可以发现问题。 Try setting the text of the RTB manually, see if it even allows that to happen. 尝试手动设置RTB的文本,看看它是否允许这种情况发生。 etc etc and so on. 等等等等。

    The issue is likely because of multi-threading as suggested on the MS forums. 问题可能是因为MS论坛上建议的多线程。 As you are requesting this operation in an asynchronous manner, it will create another thread that will handle the input so that you main application thread does not block. 当您以异步方式请求此操作时,它将创建另一个将处理输入的线程,以便您的主应用程序线程不会阻塞。

    To overcome this issue you will have to Invoke the control whose property you wish to change. 要解决此问题,您必须Invoke您希望更改其属性的控件。 You need this, as your main application thread owns the UI, and any operation on the UI cannot be done from another thread. 您需要这个,因为您的主应用程序线程拥有UI,并且UI上的任何操作都无法从另一个线程完成。

    The invoke is not complicated, and can be done in a few lines. 调用并不复杂,可以在几行中完成。

    Change the following line 更改以下行

    richTextRxMessage.Text =  szData;
    

    to

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

    This code will ask the main ui thread to update the text for richTextRxMessage rather than doing it itself. 此代码将要求主ui线程更新richTextRxMessage的文本,而不是自己执行。

    声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

     
    粤ICP备18138465号  © 2020-2024 STACKOOM.COM