0

I'm quite new to Asynchronous and I understand some general concepts, but I cannot seem to fix couple of issues.

I have the following ReceiveCallback:

public static void ReceiveCallback(IAsyncResult AR)
    {
        Socket CurrentSocket = (Socket)AR.AsyncState;
        int DataReceived = 0;

        try
        {
            DataReceived = CurrentSocket.EndReceive(AR);
        }
        catch (SocketException)
        {
            CurrentSocket.Close();
            return;
        }

        byte[] receivedBuffer = new byte[DataReceived];
        Array.Copy(Buffer, receivedBuffer, DataReceived);
        strReceived = Encoding.ASCII.GetString(receivedBuffer); // We are saving the latest receivedBuffer in a string.
        new MainWindow().Process(); // We are accessing a function in the MainWindow class
        receiveDone.Set();
        CurrentSocket.BeginReceive(Buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, CurrentSocket);
    }

Here's the "Process()" code:

public void Process()
    {
         lblReceived.Text = ClientSocket.strReceived; // Trying to set what we received in a label..
    }
  1. On the line: "new MainWindow().Process();", I receive the following exception: "Additional information: The calling thread must be STA, because many UI components require this." I've searched, and understood why it gives me the exception but several code did not work for me.

  2. The label doesn't change, I know that I am creating a new instance of MainWindow and that's why nothing shows, but I'm seeking for example on how I can make the label change by using a new instance.

Muds
  • 4,006
  • 5
  • 31
  • 53
Oh Hey
  • 5
  • 7
  • 2
    tip - please do not add tags in headers - against rules of so – Muds Mar 25 '15 at 12:27
  • As is states, a `MainWindow` is a main window, so it has to be an one and only. There **can** be only one main window. If you want to create windows from asynchronously called callbacks, then there is something wrong with your design. It's a poor approach, please reconsider this. – dymanoid Mar 25 '15 at 12:56
  • "Create windows"? I'm just creating an object to access a function found in MainWindow class. The Asychnronous method is just created on a seperate class. – Oh Hey Mar 25 '15 at 14:14
  • I don't know much about `AsyncCallback`, however the [MSDN page](https://msdn.microsoft.com/en-us/library/system.asynccallback(v=vs.110).aspx) states *"Use an AsyncCallback delegate to process the results of an asynchronous operation **in a separate thread**"*. It sounds like you're in another thread, but not the MainWindow UI thread which is the only one allowed to manipulate UI objects. Try using WPF's Dispatcher to send the code to WPF's UI thread from the callback thread. – Rachel Mar 25 '15 at 15:00

1 Answers1

0

Unfortunately, without a good, minimal, complete code example there's no way to know enough context about your question to provide a precise answer.

But some general observations can be made:

  1. Most important, if you need access to instance members of a class, it's because (or at least, should be because…it will always be, if the class is well-designed) there is already an instance of that class that you need to use. I.e. that instance has the state you need access to.

So creating a whole new instance of a class just because you couldn't otherwise access some instance member of the class (like the Process() method here) is always the wrong thing to do.

Instead, you need to provide access to that already-existing instance that has the state you need access to.

  1. Just making a broad guess based on the bits and pieces of your code that were provided, I suppose that the ReceiveCallback() method is in fact declared in your MainWindow class. If this guess is correct, then the most obvious fix for the code is to simply make the ReceiveCallback() method non-static. I.e. remove static from the method declaration. Having done so, then all you need is to call Process() directly, instead of creating a new instance of MainWindow first.

Now, in doing so you may (or may not) find that providing the method as the parameter for the original I/O operation needs fixing. Again, since you didn't provide a good code example, it's not possible to say whether or how that would be done. But I mention it just so that you don't simply give up on the idea if it doesn't work as soon as you remove the static from the declaration.


Of course, my guess might be wrong. In which case, one option would be to provide the reference to your MainWindow instance as the state object for the I/O operation. Again, how exactly that would work is impossible to say without a good code example, but the basic idea is to pass it as the last argument to the Socket.BeginReceive() method (any overload), and then retrieve it from the IAsyncResult.AsyncState property in your ReceiveCallback() method.


Note: the above is only for addressing the specific exception you are getting, as creating a new MainWindow instance is simply guaranteed to be the wrong thing to do. Since the I/O operation most likely will complete outside the UI thread, you still have an issue related to dealing with that (e.g. needing to call Dispatcher.Invoke() on code that accesses the UI itself). But one step at a time. Let's fix the immediate problem before moving on to the next.

If none of the above seems helpful, then please fix your question so that it includes a good code example, with which an actual, precise answer can be provided.

Community
  • 1
  • 1
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Thanks a lot for the useful information. You stated that I could remove the static in the ReceiveCallback(). Is there a downside of doing so? because if I'm not mistaken according to MSDN these CallBacks have to be static. I'ma go ahead and try some of the solutions you mentioned. Thanks :) Edit: The ReceiveCallback() is found on a seperate class within the namespace of the program. Per say; MainWindow is found in MainWindow.xaml.cs and the ReceiveCallback() is found in ClientSocket.cs – Oh Hey Mar 25 '15 at 16:09
  • Apparentely using ReceiveCallback() in the MainWindow class and removing static keyword in the ReceiveCallback() method fixed the issue. In order to fix the thread issue I used the following code; http://stackoverflow.com/a/21539361/4135053 – Oh Hey Mar 25 '15 at 16:24
  • @OhHey: "these CallBacks have to be static" -- not sure what you saw in MSDN that made you think that was the case, but it's definitely not true. The callback can be any delegate instance of the correct signature, and the target of that delegate can be static or non-static. There's not any inherent downside in using a non-static method, and in fact there's the obvious upside that using a non-static method makes it easier to access instance members. :) – Peter Duniho Mar 25 '15 at 17:06
  • Very helpful of you Peter. Thanks again! – Oh Hey Mar 25 '15 at 17:49